Merge branch 'develop' into purchase_inv_due

This commit is contained in:
Marica 2020-06-19 18:44:53 +05:30 committed by GitHub
commit 47a4567301
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
485 changed files with 16146 additions and 5839 deletions

14
.github/workflows/docker-release.yml vendored Normal file
View File

@ -0,0 +1,14 @@
name: Trigger Docker build on release
on:
release:
types: [created]
jobs:
curl:
runs-on: ubuntu-latest
container:
image: alpine:latest
steps:
- name: curl
run: |
apk add curl bash
curl -s -X POST -H "Content-Type: application/json" -H "Accept: application/json" -H "Travis-API-Version: 3" -H "Authorization: token ${{ secrets.TRAVIS_CI_TOKEN }}" -d '{"request":{"branch":"master"}}' https://api.travis-ci.com/repo/frappe%2Ffrappe_docker/requests

View File

@ -3,17 +3,16 @@
# These owners will be the default owners for everything in # These owners will be the default owners for everything in
# the repo. Unless a later match takes precedence, # the repo. Unless a later match takes precedence,
* @nabinhait manufacturing/ @rohitwaghchaure @marination
manufacturing/ @rohitwaghchaure
accounts/ @deepeshgarg007 @nextchamp-saqib accounts/ @deepeshgarg007 @nextchamp-saqib
loan_management/ @deepeshgarg007 loan_management/ @deepeshgarg007 @rohitwaghchaure
pos* @nextchamp-saqib pos* @nextchamp-saqib @rohitwaghchaure
assets/ @nextchamp-saqib assets/ @nextchamp-saqib @deepeshgarg007
stock/ @marination @rohitwaghchaure stock/ @marination @rohitwaghchaure
buying/ @marination @rohitwaghchaure buying/ @marination @deepeshgarg007
hr/ @Anurag810 hr/ @Anurag810 @rohitwaghchaure
projects/ @hrwX projects/ @hrwX @nextchamp-saqib
support/ @hrwX support/ @hrwX @marination
healthcare/ @ruchamahabal healthcare/ @ruchamahabal @marination
erpnext_integrations/ @Mangesh-Khairnar erpnext_integrations/ @Mangesh-Khairnar @nextchamp-saqib
requirements.txt @gavindsouza requirements.txt @gavindsouza

View File

@ -1,127 +1,284 @@
# Copyright (c) 2020, Frappe Technologies Pvt. Ltd. and Contributors # Copyright (c) 2020, 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 erpnext import get_default_company
import frappe import frappe
import json import json
from frappe.utils import nowdate, add_months, get_date_str
from frappe import _
from erpnext.accounts.utils import get_fiscal_year, get_account_name, FiscalYearError
def _get_fiscal_year(date=None):
try:
fiscal_year = get_fiscal_year(date=nowdate(), as_dict=True)
return fiscal_year
except FiscalYearError:
#if no fiscal year for current date then get default fiscal year
try:
fiscal_year = get_fiscal_year(as_dict=True)
return fiscal_year
except FiscalYearError:
#if still no fiscal year found then no accounting data created, return
return None
def get_company_for_dashboards():
company = frappe.defaults.get_defaults().company
if company:
return company
else:
company_list = frappe.get_list("Company")
if company_list:
return company_list[0].name
return None
def get_data(): def get_data():
data = frappe._dict({
"dashboards": [], fiscal_year = _get_fiscal_year(nowdate())
"charts": []
if not fiscal_year:
return frappe._dict()
return frappe._dict({
"dashboards": get_dashboards(),
"charts": get_charts(fiscal_year),
"number_cards": get_number_cards(fiscal_year)
}) })
company = get_company_for_dashboards()
if company:
company_doc = frappe.get_doc("Company", company)
data.dashboards = get_dashboards()
data.charts = get_charts(company_doc)
return data
def get_dashboards(): def get_dashboards():
return [{ return [{
"name": "Accounts", "name": "Accounts",
"dashboard_name": "Accounts", "dashboard_name": "Accounts",
"doctype": "Dashboard",
"charts": [ "charts": [
{ "chart": "Outgoing Bills (Sales Invoice)" }, { "chart": "Profit and Loss" , "width": "Full"},
{ "chart": "Incoming Bills (Purchase Invoice)" }, { "chart": "Incoming Bills (Purchase Invoice)", "width": "Half"},
{ "chart": "Bank Balance" }, { "chart": "Outgoing Bills (Sales Invoice)", "width": "Half"},
{ "chart": "Income" }, { "chart": "Accounts Receivable Ageing", "width": "Half"},
{ "chart": "Expenses" } { "chart": "Accounts Payable Ageing", "width": "Half"},
{ "chart": "Budget Variance", "width": "Full"},
{ "chart": "Bank Balance", "width": "Full"}
],
"cards": [
{"card": "Total Outgoing Bills"},
{"card": "Total Incoming Bills"},
{"card": "Total Incoming Payment"},
{"card": "Total Outgoing Payment"}
] ]
}] }]
def get_charts(company): def get_charts(fiscal_year):
income_account = company.default_income_account or get_account("Income Account", company.name) company = frappe.get_doc("Company", get_company_for_dashboards())
expense_account = company.default_expense_account or get_account("Expense Account", company.name) bank_account = company.default_bank_account or get_account_name("Bank", company=company.name)
bank_account = company.default_bank_account or get_account("Bank", company.name) default_cost_center = company.cost_center
return [ return [
{ {
"doctype": "Dashboard Chart", "doctype": "Dashboard Charts",
"time_interval": "Quarterly", "name": "Profit and Loss",
"name": "Income",
"chart_name": "Income",
"timespan": "Last Year",
"color": None,
"filters_json": json.dumps({"company": company.name, "account": income_account}),
"source": "Account Balance Timeline",
"chart_type": "Custom",
"timeseries": 1,
"owner": "Administrator", "owner": "Administrator",
"type": "Line" "report_name": "Profit and Loss Statement",
}, "filters_json": json.dumps({
{ "company": company.name,
"doctype": "Dashboard Chart", "filter_based_on": "Fiscal Year",
"time_interval": "Quarterly", "from_fiscal_year": fiscal_year.get('name'),
"name": "Expenses", "to_fiscal_year": fiscal_year.get('name'),
"chart_name": "Expenses", "periodicity": "Monthly",
"timespan": "Last Year", "include_default_book_entries": 1
"color": None, }),
"filters_json": json.dumps({"company": company.name, "account": expense_account}), "type": "Bar",
"source": "Account Balance Timeline", 'timeseries': 0,
"chart_type": "Custom", "chart_type": "Report",
"timeseries": 1, "chart_name": _("Profit and Loss"),
"owner": "Administrator", "is_custom": 1,
"type": "Line" "is_public": 1
},
{
"doctype": "Dashboard Chart",
"time_interval": "Quarterly",
"name": "Bank Balance",
"chart_name": "Bank Balance",
"timespan": "Last Year",
"color": "#ffb868",
"filters_json": json.dumps({"company": company.name, "account": bank_account}),
"source": "Account Balance Timeline",
"chart_type": "Custom",
"timeseries": 1,
"owner": "Administrator",
"type": "Line"
}, },
{ {
"doctype": "Dashboard Chart", "doctype": "Dashboard Chart",
"time_interval": "Monthly", "time_interval": "Monthly",
"name": "Incoming Bills (Purchase Invoice)", "name": "Incoming Bills (Purchase Invoice)",
"chart_name": "Incoming Bills (Purchase Invoice)", "chart_name": _("Incoming Bills (Purchase Invoice)"),
"timespan": "Last Year", "timespan": "Last Year",
"color": "#a83333", "color": "#a83333",
"value_based_on": "base_grand_total", "value_based_on": "base_net_total",
"filters_json": json.dumps({}), "filters_json": json.dumps([["Purchase Invoice", "docstatus", "=", 1]]),
"chart_type": "Sum", "chart_type": "Sum",
"timeseries": 1, "timeseries": 1,
"based_on": "posting_date", "based_on": "posting_date",
"owner": "Administrator", "owner": "Administrator",
"document_type": "Purchase Invoice", "document_type": "Purchase Invoice",
"type": "Bar" "type": "Bar",
"width": "Half",
"is_public": 1
}, },
{ {
"doctype": "Dashboard Chart", "doctype": "Dashboard Chart",
"time_interval": "Monthly",
"name": "Outgoing Bills (Sales Invoice)", "name": "Outgoing Bills (Sales Invoice)",
"chart_name": "Outgoing Bills (Sales Invoice)", "time_interval": "Monthly",
"chart_name": _("Outgoing Bills (Sales Invoice)"),
"timespan": "Last Year", "timespan": "Last Year",
"color": "#7b933d", "color": "#7b933d",
"value_based_on": "base_grand_total", "value_based_on": "base_net_total",
"filters_json": json.dumps({}), "filters_json": json.dumps([["Sales Invoice", "docstatus", "=", 1]]),
"chart_type": "Sum", "chart_type": "Sum",
"timeseries": 1, "timeseries": 1,
"based_on": "posting_date", "based_on": "posting_date",
"owner": "Administrator", "owner": "Administrator",
"document_type": "Sales Invoice", "document_type": "Sales Invoice",
"type": "Bar" "type": "Bar",
} "width": "Half",
"is_public": 1
},
{
"doctype": "Dashboard Charts",
"name": "Accounts Receivable Ageing",
"owner": "Administrator",
"report_name": "Accounts Receivable",
"filters_json": json.dumps({
"company": company.name,
"report_date": nowdate(),
"ageing_based_on": "Due Date",
"range1": 30,
"range2": 60,
"range3": 90,
"range4": 120
}),
"type": "Donut",
'timeseries': 0,
"chart_type": "Report",
"chart_name": _("Accounts Receivable Ageing"),
"is_custom": 1,
"is_public": 1
},
{
"doctype": "Dashboard Charts",
"name": "Accounts Payable Ageing",
"owner": "Administrator",
"report_name": "Accounts Payable",
"filters_json": json.dumps({
"company": company.name,
"report_date": nowdate(),
"ageing_based_on": "Due Date",
"range1": 30,
"range2": 60,
"range3": 90,
"range4": 120
}),
"type": "Donut",
'timeseries': 0,
"chart_type": "Report",
"chart_name": _("Accounts Payable Ageing"),
"is_custom": 1,
"is_public": 1
},
{
"doctype": "Dashboard Charts",
"name": "Budget Variance",
"owner": "Administrator",
"report_name": "Budget Variance Report",
"filters_json": json.dumps({
"company": company.name,
"from_fiscal_year": fiscal_year.get('name'),
"to_fiscal_year": fiscal_year.get('name'),
"period": "Monthly",
"budget_against": "Cost Center"
}),
"type": "Bar",
"timeseries": 0,
"chart_type": "Report",
"chart_name": _("Budget Variance"),
"is_custom": 1,
"is_public": 1
},
{
"doctype": "Dashboard Charts",
"name": "Bank Balance",
"time_interval": "Quarterly",
"chart_name": "Bank Balance",
"timespan": "Last Year",
"filters_json": json.dumps({
"company": company.name,
"account": bank_account
}),
"source": "Account Balance Timeline",
"chart_type": "Custom",
"timeseries": 1,
"owner": "Administrator",
"type": "Line",
"width": "Half",
"is_public": 1
},
] ]
def get_account(account_type, company): def get_number_cards(fiscal_year):
accounts = frappe.get_list("Account", filters={"account_type": account_type, "company": company})
if accounts:
return accounts[0].name
def get_company_for_dashboards(): year_start_date = get_date_str(fiscal_year.get("year_start_date"))
company = get_default_company() year_end_date = get_date_str(fiscal_year.get("year_end_date"))
if not company: return [
company_list = frappe.get_list("Company") {
if company_list: "doctype": "Number Card",
company = company_list[0].name "document_type": "Payment Entry",
return company "name": "Total Incoming Payment",
"filters_json": json.dumps([
['Payment Entry', 'docstatus', '=', 1],
['Payment Entry', 'posting_date', 'between', [year_start_date, year_end_date]],
['Payment Entry', 'payment_type', '=', 'Receive']
]),
"label": _("Total Incoming Payment"),
"function": "Sum",
"aggregate_function_based_on": "base_received_amount",
"is_public": 1,
"is_custom": 1,
"show_percentage_stats": 1,
"stats_time_interval": "Monthly"
},
{
"doctype": "Number Card",
"document_type": "Payment Entry",
"name": "Total Outgoing Payment",
"filters_json": json.dumps([
['Payment Entry', 'docstatus', '=', 1],
['Payment Entry', 'posting_date', 'between', [year_start_date, year_end_date]],
['Payment Entry', 'payment_type', '=', 'Pay']
]),
"label": _("Total Outgoing Payment"),
"function": "Sum",
"aggregate_function_based_on": "base_paid_amount",
"is_public": 1,
"is_custom": 1,
"show_percentage_stats": 1,
"stats_time_interval": "Monthly"
},
{
"doctype": "Number Card",
"document_type": "Sales Invoice",
"name": "Total Outgoing Bills",
"filters_json": json.dumps([
['Sales Invoice', 'docstatus', '=', 1],
['Sales Invoice', 'posting_date', 'between', [year_start_date, year_end_date]]
]),
"label": _("Total Outgoing Bills"),
"function": "Sum",
"aggregate_function_based_on": "base_net_total",
"is_public": 1,
"is_custom": 1,
"show_percentage_stats": 1,
"stats_time_interval": "Monthly"
},
{
"doctype": "Number Card",
"document_type": "Purchase Invoice",
"name": "Total Incoming Bills",
"filters_json": json.dumps([
['Purchase Invoice', 'docstatus', '=', 1],
['Purchase Invoice', 'posting_date', 'between', [year_start_date, year_end_date]]
]),
"label": _("Total Incoming Bills"),
"function": "Sum",
"aggregate_function_based_on": "base_net_total",
"is_public": 1,
"is_custom": 1,
"show_percentage_stats": 1,
"stats_time_interval": "Monthly"
}
]

View File

@ -199,10 +199,13 @@ def book_deferred_income_or_expense(doc, deferred_process, posting_date=None):
if item.get(enable_check): if item.get(enable_check):
_book_deferred_revenue_or_expense(item) _book_deferred_revenue_or_expense(item)
def process_deferred_accounting(posting_date=today()): def process_deferred_accounting(posting_date=None):
''' Converts deferred income/expense into income/expense ''' Converts deferred income/expense into income/expense
Executed via background jobs on every month end ''' Executed via background jobs on every month end '''
if not posting_date:
posting_date = today()
if not cint(frappe.db.get_singles_value('Accounts Settings', 'automatically_process_deferred_accounting_entry')): if not cint(frappe.db.get_singles_value('Accounts Settings', 'automatically_process_deferred_accounting_entry')):
return return

View File

@ -13,12 +13,12 @@
{ {
"hidden": 0, "hidden": 0,
"label": "Accounts Receivable", "label": "Accounts Receivable",
"links": "[\n {\n \"description\": \"Bills raised to Customers.\",\n \"label\": \"Sales Invoice\",\n \"name\": \"Sales Invoice\",\n \"onboard\": 1,\n \"type\": \"doctype\"\n },\n {\n \"description\": \"Customer database.\",\n \"label\": \"Customer\",\n \"name\": \"Customer\",\n \"onboard\": 1,\n \"type\": \"doctype\"\n },\n {\n \"description\": \"Bank/Cash transactions against party or for internal transfer\",\n \"label\": \"Payment Entry\",\n \"name\": \"Payment Entry\",\n \"type\": \"doctype\"\n },\n {\n \"description\": \"Payment Request\",\n \"label\": \"Payment Request\",\n \"name\": \"Payment Request\",\n \"type\": \"doctype\"\n },\n {\n \"dependencies\": [\n \"Sales Invoice\"\n ],\n \"doctype\": \"Sales Invoice\",\n \"is_query_report\": true,\n \"label\": \"Accounts Receivable\",\n \"name\": \"Accounts Receivable\",\n \"type\": \"report\"\n },\n {\n \"dependencies\": [\n \"Sales Invoice\"\n ],\n \"doctype\": \"Sales Invoice\",\n \"is_query_report\": true,\n \"label\": \"Accounts Receivable Summary\",\n \"name\": \"Accounts Receivable Summary\",\n \"type\": \"report\"\n },\n {\n \"dependencies\": [\n \"Sales Invoice\"\n ],\n \"doctype\": \"Sales Invoice\",\n \"is_query_report\": true,\n \"label\": \"Sales Register\",\n \"name\": \"Sales Register\",\n \"type\": \"report\"\n },\n {\n \"dependencies\": [\n \"Sales Invoice\"\n ],\n \"doctype\": \"Sales Invoice\",\n \"is_query_report\": true,\n \"label\": \"Item-wise Sales Register\",\n \"name\": \"Item-wise Sales Register\",\n \"type\": \"report\"\n },\n {\n \"dependencies\": [\n \"Sales Invoice\"\n ],\n \"doctype\": \"Sales Invoice\",\n \"is_query_report\": true,\n \"label\": \"Ordered Items To Be Billed\",\n \"name\": \"Ordered Items To Be Billed\",\n \"type\": \"report\"\n },\n {\n \"dependencies\": [\n \"Sales Invoice\"\n ],\n \"doctype\": \"Sales Invoice\",\n \"is_query_report\": true,\n \"label\": \"Delivered Items To Be Billed\",\n \"name\": \"Delivered Items To Be Billed\",\n \"type\": \"report\"\n }\n]" "links": "[\n {\n \"description\": \"Bills raised to Customers.\",\n \"label\": \"Sales Invoice\",\n \"name\": \"Sales Invoice\",\n \"onboard\": 1,\n \"type\": \"doctype\"\n },\n {\n \"description\": \"Customer database.\",\n \"label\": \"Customer\",\n \"name\": \"Customer\",\n \"onboard\": 1,\n \"type\": \"doctype\"\n },\n {\n \"description\": \"Bank/Cash transactions against party or for internal transfer\",\n \"label\": \"Payment Entry\",\n \"name\": \"Payment Entry\",\n \"type\": \"doctype\"\n },\n {\n \"description\": \"Payment Request\",\n \"label\": \"Payment Request\",\n \"name\": \"Payment Request\",\n \"type\": \"doctype\"\n },\n {\n \"dependencies\": [\n \"Sales Invoice\"\n ],\n \"doctype\": \"Sales Invoice\",\n \"is_query_report\": true,\n \"label\": \"Accounts Receivable\",\n \"name\": \"Accounts Receivable\",\n \"type\": \"report\"\n },\n {\n \"dependencies\": [\n \"Sales Invoice\"\n ],\n \"doctype\": \"Sales Invoice\",\n \"is_query_report\": true,\n \"label\": \"Accounts Receivable Summary\",\n \"name\": \"Accounts Receivable Summary\",\n \"type\": \"report\"\n },\n {\n \"dependencies\": [\n \"Sales Invoice\"\n ],\n \"doctype\": \"Sales Invoice\",\n \"is_query_report\": true,\n \"label\": \"Sales Register\",\n \"name\": \"Sales Register\",\n \"type\": \"report\"\n },\n {\n \"dependencies\": [\n \"Sales Invoice\"\n ],\n \"doctype\": \"Sales Invoice\",\n \"is_query_report\": true,\n \"label\": \"Item-wise Sales Register\",\n \"name\": \"Item-wise Sales Register\",\n \"type\": \"report\"\n },\n {\n \"dependencies\": [\n \"Sales Invoice\"\n ],\n \"doctype\": \"Sales Order\",\n \"is_query_report\": true,\n \"label\": \"Sales Order Analysis\",\n \"name\": \"Sales Order Analysis\",\n \"type\": \"report\"\n },\n {\n \"dependencies\": [\n \"Sales Invoice\"\n ],\n \"doctype\": \"Sales Invoice\",\n \"is_query_report\": true,\n \"label\": \"Delivered Items To Be Billed\",\n \"name\": \"Delivered Items To Be Billed\",\n \"type\": \"report\"\n }\n]"
}, },
{ {
"hidden": 0, "hidden": 0,
"label": "Accounts Payable", "label": "Accounts Payable",
"links": "[\n {\n \"description\": \"Bills raised by Suppliers.\",\n \"label\": \"Purchase Invoice\",\n \"name\": \"Purchase Invoice\",\n \"onboard\": 1,\n \"type\": \"doctype\"\n },\n {\n \"description\": \"Supplier database.\",\n \"label\": \"Supplier\",\n \"name\": \"Supplier\",\n \"onboard\": 1,\n \"type\": \"doctype\"\n },\n {\n \"description\": \"Bank/Cash transactions against party or for internal transfer\",\n \"label\": \"Payment Entry\",\n \"name\": \"Payment Entry\",\n \"type\": \"doctype\"\n },\n {\n \"dependencies\": [\n \"Purchase Invoice\"\n ],\n \"doctype\": \"Purchase Invoice\",\n \"is_query_report\": true,\n \"label\": \"Accounts Payable\",\n \"name\": \"Accounts Payable\",\n \"type\": \"report\"\n },\n {\n \"dependencies\": [\n \"Purchase Invoice\"\n ],\n \"doctype\": \"Purchase Invoice\",\n \"is_query_report\": true,\n \"label\": \"Accounts Payable Summary\",\n \"name\": \"Accounts Payable Summary\",\n \"type\": \"report\"\n },\n {\n \"dependencies\": [\n \"Purchase Invoice\"\n ],\n \"doctype\": \"Purchase Invoice\",\n \"is_query_report\": true,\n \"label\": \"Purchase Register\",\n \"name\": \"Purchase Register\",\n \"type\": \"report\"\n },\n {\n \"dependencies\": [\n \"Purchase Invoice\"\n ],\n \"doctype\": \"Purchase Invoice\",\n \"is_query_report\": true,\n \"label\": \"Item-wise Purchase Register\",\n \"name\": \"Item-wise Purchase Register\",\n \"type\": \"report\"\n },\n {\n \"dependencies\": [\n \"Purchase Invoice\"\n ],\n \"doctype\": \"Purchase Invoice\",\n \"is_query_report\": true,\n \"label\": \"Purchase Order Items To Be Billed\",\n \"name\": \"Purchase Order Items To Be Billed\",\n \"type\": \"report\"\n },\n {\n \"dependencies\": [\n \"Purchase Invoice\"\n ],\n \"doctype\": \"Purchase Invoice\",\n \"is_query_report\": true,\n \"label\": \"Received Items To Be Billed\",\n \"name\": \"Received Items To Be Billed\",\n \"type\": \"report\"\n }\n]" "links": "[\n {\n \"description\": \"Bills raised by Suppliers.\",\n \"label\": \"Purchase Invoice\",\n \"name\": \"Purchase Invoice\",\n \"onboard\": 1,\n \"type\": \"doctype\"\n },\n {\n \"description\": \"Supplier database.\",\n \"label\": \"Supplier\",\n \"name\": \"Supplier\",\n \"onboard\": 1,\n \"type\": \"doctype\"\n },\n {\n \"description\": \"Bank/Cash transactions against party or for internal transfer\",\n \"label\": \"Payment Entry\",\n \"name\": \"Payment Entry\",\n \"type\": \"doctype\"\n },\n {\n \"dependencies\": [\n \"Purchase Invoice\"\n ],\n \"doctype\": \"Purchase Invoice\",\n \"is_query_report\": true,\n \"label\": \"Accounts Payable\",\n \"name\": \"Accounts Payable\",\n \"type\": \"report\"\n },\n {\n \"dependencies\": [\n \"Purchase Invoice\"\n ],\n \"doctype\": \"Purchase Invoice\",\n \"is_query_report\": true,\n \"label\": \"Accounts Payable Summary\",\n \"name\": \"Accounts Payable Summary\",\n \"type\": \"report\"\n },\n {\n \"dependencies\": [\n \"Purchase Invoice\"\n ],\n \"doctype\": \"Purchase Invoice\",\n \"is_query_report\": true,\n \"label\": \"Purchase Register\",\n \"name\": \"Purchase Register\",\n \"type\": \"report\"\n },\n {\n \"dependencies\": [\n \"Purchase Invoice\"\n ],\n \"doctype\": \"Purchase Invoice\",\n \"is_query_report\": true,\n \"label\": \"Item-wise Purchase Register\",\n \"name\": \"Item-wise Purchase Register\",\n \"type\": \"report\"\n },\n {\n \"dependencies\": [\n \"Purchase Order\"\n ],\n \"doctype\": \"Purchase Order\",\n \"is_query_report\": true,\n \"label\": \"Purchase Order Analysis\",\n \"name\": \"Purchase Order Analysis\",\n \"type\": \"report\"\n },\n {\n \"dependencies\": [\n \"Purchase Invoice\"\n ],\n \"doctype\": \"Purchase Invoice\",\n \"is_query_report\": true,\n \"label\": \"Received Items To Be Billed\",\n \"name\": \"Received Items To Be Billed\",\n \"type\": \"report\"\n }\n]"
}, },
{ {
"hidden": 0, "hidden": 0,
@ -45,11 +45,6 @@
"label": "Bank Statement", "label": "Bank Statement",
"links": "[\n {\n \"label\": \"Bank\",\n \"name\": \"Bank\",\n \"type\": \"doctype\"\n },\n {\n \"label\": \"Bank Account\",\n \"name\": \"Bank Account\",\n \"type\": \"doctype\"\n },\n {\n \"label\": \"Bank Statement Transaction Entry\",\n \"name\": \"Bank Statement Transaction Entry\",\n \"type\": \"doctype\"\n },\n {\n \"label\": \"Bank Statement Settings\",\n \"name\": \"Bank Statement Settings\",\n \"type\": \"doctype\"\n }\n]" "links": "[\n {\n \"label\": \"Bank\",\n \"name\": \"Bank\",\n \"type\": \"doctype\"\n },\n {\n \"label\": \"Bank Account\",\n \"name\": \"Bank Account\",\n \"type\": \"doctype\"\n },\n {\n \"label\": \"Bank Statement Transaction Entry\",\n \"name\": \"Bank Statement Transaction Entry\",\n \"type\": \"doctype\"\n },\n {\n \"label\": \"Bank Statement Settings\",\n \"name\": \"Bank Statement Settings\",\n \"type\": \"doctype\"\n }\n]"
}, },
{
"hidden": 0,
"links": "[\n {\n \"description\": \"Match non-linked Invoices and Payments.\",\n \"label\": \"Match Payments with Invoices\",\n \"name\": \"Payment Reconciliation\",\n \"type\": \"doctype\"\n },\n {\n \"description\": \"Update bank payment dates with journals.\",\n \"label\": \"Update Bank Clearance Dates\",\n \"name\": \"Bank Clearance\",\n \"type\": \"doctype\"\n },\n {\n \"label\": \"Invoice Discounting\",\n \"name\": \"Invoice Discounting\",\n \"type\": \"doctype\"\n },\n {\n \"dependencies\": [\n \"Journal Entry\"\n ],\n \"doctype\": \"Journal Entry\",\n \"is_query_report\": true,\n \"label\": \"Bank Reconciliation Statement\",\n \"name\": \"Bank Reconciliation Statement\",\n \"type\": \"report\"\n },\n {\n \"icon\": \"fa fa-bar-chart\",\n \"label\": \"Bank Reconciliation\",\n \"name\": \"bank-reconciliation\",\n \"type\": \"page\"\n },\n {\n \"dependencies\": [\n \"Journal Entry\"\n ],\n \"doctype\": \"Journal Entry\",\n \"is_query_report\": true,\n \"label\": \"Bank Clearance Summary\",\n \"name\": \"Bank Clearance Summary\",\n \"type\": \"report\"\n },\n {\n \"label\": \"Bank Guarantee\",\n \"name\": \"Bank Guarantee\",\n \"type\": \"doctype\"\n },\n {\n \"description\": \"Setup cheque dimensions for printing\",\n \"label\": \"Cheque Print Template\",\n \"name\": \"Cheque Print Template\",\n \"type\": \"doctype\"\n }\n]",
"title": "Banking and Payments"
},
{ {
"hidden": 0, "hidden": 0,
"label": "Subscription Management", "label": "Subscription Management",
@ -89,8 +84,8 @@
"category": "Modules", "category": "Modules",
"charts": [ "charts": [
{ {
"chart_name": "Bank Balance", "chart_name": "Profit and Loss",
"label": "Bank Balance" "label": "Profit and Loss"
} }
], ],
"creation": "2020-03-02 15:41:59.515192", "creation": "2020-03-02 15:41:59.515192",
@ -99,23 +94,34 @@
"docstatus": 0, "docstatus": 0,
"doctype": "Desk Page", "doctype": "Desk Page",
"extends_another_page": 0, "extends_another_page": 0,
"icon": "", "hide_custom": 0,
"idx": 0, "idx": 0,
"is_standard": 1, "is_standard": 1,
"label": "Accounting", "label": "Accounting",
"modified": "2020-04-29 12:17:34.844397", "modified": "2020-06-19 12:42:44.054598",
"modified_by": "Administrator", "modified_by": "Administrator",
"module": "Accounts", "module": "Accounts",
"name": "Accounting", "name": "Accounting",
"onboarding": "Accounts",
"owner": "Administrator", "owner": "Administrator",
"pin_to_bottom": 0, "pin_to_bottom": 0,
"pin_to_top": 0, "pin_to_top": 0,
"shortcuts": [ "shortcuts": [
{ {
"label": "Account", "label": "Chart Of Accounts",
"link_to": "Account", "link_to": "Account",
"type": "DocType" "type": "DocType"
}, },
{
"label": "Sales Invoice",
"link_to": "Sales Invoice",
"type": "DocType"
},
{
"label": "Purchase Invoice",
"link_to": "Purchase Invoice",
"type": "DocType"
},
{ {
"label": "Journal Entry", "label": "Journal Entry",
"link_to": "Journal Entry", "link_to": "Journal Entry",
@ -136,15 +142,15 @@
"link_to": "General Ledger", "link_to": "General Ledger",
"type": "Report" "type": "Report"
}, },
{
"label": "Profit and Loss Statement",
"link_to": "Profit and Loss Statement",
"type": "Report"
},
{ {
"label": "Trial Balance", "label": "Trial Balance",
"link_to": "Trial Balance", "link_to": "Trial Balance",
"type": "Report" "type": "Report"
},
{
"label": "Dashboard",
"link_to": "Accounts",
"type": "Dashboard"
} }
] ]
} }

View File

@ -14,6 +14,9 @@ frappe.treeview_settings["Account"] = {
on_change: function() { on_change: function() {
var me = frappe.treeview_settings['Account'].treeview; var me = frappe.treeview_settings['Account'].treeview;
var company = me.page.fields_dict.company.get_value(); var company = me.page.fields_dict.company.get_value();
if (!company) {
frappe.throw(__("Please set a Company"));
}
frappe.call({ frappe.call({
method: "erpnext.accounts.doctype.account.account.get_root_company", method: "erpnext.accounts.doctype.account.account.get_root_company",
args: { args: {

View File

@ -72,7 +72,11 @@ def make_dimension_in_accounting_doctypes(doc):
if doctype == "Budget": if doctype == "Budget":
add_dimension_to_budget_doctype(df, doc) add_dimension_to_budget_doctype(df, doc)
else: else:
create_custom_field(doctype, df) meta = frappe.get_meta(doctype, cached=False)
fieldnames = [d.fieldname for d in meta.get("fields")]
if df['fieldname'] not in fieldnames:
create_custom_field(doctype, df)
count += 1 count += 1

View File

@ -14,7 +14,18 @@ frappe.ui.form.on('Cost Center', {
is_group: 1 is_group: 1
} }
} }
}) });
frm.set_query("cost_center", "distributed_cost_center", function() {
return {
filters: {
company: frm.doc.company,
is_group: 0,
enable_distributed_cost_center: 0,
name: ['!=', frm.doc.name]
}
};
});
}, },
refresh: function(frm) { refresh: function(frm) {
if (!frm.is_new()) { if (!frm.is_new()) {

View File

@ -16,6 +16,9 @@
"cb0", "cb0",
"is_group", "is_group",
"disabled", "disabled",
"section_break_9",
"enable_distributed_cost_center",
"distributed_cost_center",
"lft", "lft",
"rgt", "rgt",
"old_parent" "old_parent"
@ -119,13 +122,31 @@
"fieldname": "disabled", "fieldname": "disabled",
"fieldtype": "Check", "fieldtype": "Check",
"label": "Disabled" "label": "Disabled"
},
{
"default": "0",
"fieldname": "enable_distributed_cost_center",
"fieldtype": "Check",
"label": "Enable Distributed Cost Center"
},
{
"depends_on": "eval:doc.is_group==0",
"fieldname": "section_break_9",
"fieldtype": "Section Break"
},
{
"depends_on": "enable_distributed_cost_center",
"fieldname": "distributed_cost_center",
"fieldtype": "Table",
"label": "Distributed Cost Center",
"options": "Distributed Cost Center"
} }
], ],
"icon": "fa fa-money", "icon": "fa fa-money",
"idx": 1, "idx": 1,
"is_tree": 1, "is_tree": 1,
"links": [], "links": [],
"modified": "2020-04-29 16:09:30.025214", "modified": "2020-06-17 16:09:30.025214",
"modified_by": "Administrator", "modified_by": "Administrator",
"module": "Accounts", "module": "Accounts",
"name": "Cost Center", "name": "Cost Center",

View File

@ -19,6 +19,24 @@ class CostCenter(NestedSet):
def validate(self): def validate(self):
self.validate_mandatory() self.validate_mandatory()
self.validate_parent_cost_center() self.validate_parent_cost_center()
self.validate_distributed_cost_center()
def validate_distributed_cost_center(self):
if cint(self.enable_distributed_cost_center):
if not self.distributed_cost_center:
frappe.throw(_("Please enter distributed cost center"))
if sum(x.percentage_allocation for x in self.distributed_cost_center) != 100:
frappe.throw(_("Total percentage allocation for distributed cost center should be equal to 100"))
if not self.get('__islocal'):
if not cint(frappe.get_cached_value("Cost Center", {"name": self.name}, "enable_distributed_cost_center")) \
and self.check_if_part_of_distributed_cost_center():
frappe.throw(_("Cannot enable Distributed Cost Center for a Cost Center already allocated in another Distributed Cost Center"))
if next((True for x in self.distributed_cost_center if x.cost_center == x.parent), False):
frappe.throw(_("Parent Cost Center cannot be added in Distributed Cost Center"))
if check_if_distributed_cost_center_enabled(list(x.cost_center for x in self.distributed_cost_center)):
frappe.throw(_("A Distributed Cost Center cannot be added in the Distributed Cost Center allocation table."))
else:
self.distributed_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:
@ -43,12 +61,15 @@ class CostCenter(NestedSet):
return 1 return 1
def convert_ledger_to_group(self): def convert_ledger_to_group(self):
if cint(self.enable_distributed_cost_center):
frappe.throw(_("Cost Center with enabled distributed cost center can not be converted to group"))
if self.check_if_part_of_distributed_cost_center():
frappe.throw(_("Cost Center Already Allocated in a Distributed Cost Center cannot be converted to group"))
if self.check_gle_exists(): if self.check_gle_exists():
frappe.throw(_("Cost Center with existing transactions can not be converted to group")) frappe.throw(_("Cost Center with existing transactions can not be converted to group"))
else: self.is_group = 1
self.is_group = 1 self.save()
self.save() return 1
return 1
def check_gle_exists(self): def check_gle_exists(self):
return frappe.db.get_value("GL Entry", {"cost_center": self.name}) return frappe.db.get_value("GL Entry", {"cost_center": self.name})
@ -57,6 +78,9 @@ class CostCenter(NestedSet):
return frappe.db.sql("select name from `tabCost Center` where \ return frappe.db.sql("select name from `tabCost Center` where \
parent_cost_center = %s and docstatus != 2", self.name) parent_cost_center = %s and docstatus != 2", self.name)
def check_if_part_of_distributed_cost_center(self):
return frappe.db.get_value("Distributed Cost Center", {"cost_center": self.name})
def before_rename(self, olddn, newdn, merge=False): def before_rename(self, olddn, newdn, merge=False):
# Add company abbr if not provided # Add company abbr if not provided
from erpnext.setup.doctype.company.company import get_name_with_abbr from erpnext.setup.doctype.company.company import get_name_with_abbr
@ -100,3 +124,7 @@ def get_name_with_number(new_account, account_number):
if account_number and not new_account[0].isdigit(): if account_number and not new_account[0].isdigit():
new_account = account_number + " - " + new_account new_account = account_number + " - " + new_account
return new_account return new_account
def check_if_distributed_cost_center_enabled(cost_center_list):
value_list = frappe.get_list("Cost Center", {"name": ["in", cost_center_list]}, "enable_distributed_cost_center", as_list=1)
return next((True for x in value_list if x[0]), False)

View File

@ -22,6 +22,33 @@ class TestCostCenter(unittest.TestCase):
self.assertRaises(frappe.ValidationError, cost_center.save) self.assertRaises(frappe.ValidationError, cost_center.save)
def test_validate_distributed_cost_center(self):
if not frappe.db.get_value('Cost Center', {'name': '_Test Cost Center - _TC'}):
frappe.get_doc(test_records[0]).insert()
if not frappe.db.get_value('Cost Center', {'name': '_Test Cost Center 2 - _TC'}):
frappe.get_doc(test_records[1]).insert()
invalid_distributed_cost_center = frappe.get_doc({
"company": "_Test Company",
"cost_center_name": "_Test Distributed Cost Center",
"doctype": "Cost Center",
"is_group": 0,
"parent_cost_center": "_Test Company - _TC",
"enable_distributed_cost_center": 1,
"distributed_cost_center": [{
"cost_center": "_Test Cost Center - _TC",
"percentage_allocation": 40
}, {
"cost_center": "_Test Cost Center 2 - _TC",
"percentage_allocation": 50
}
]
})
self.assertRaises(frappe.ValidationError, invalid_distributed_cost_center.save)
def create_cost_center(**args): def create_cost_center(**args):
args = frappe._dict(args) args = frappe._dict(args)
if args.cost_center_name: if args.cost_center_name:

View File

@ -0,0 +1,40 @@
{
"actions": [],
"creation": "2020-03-19 12:34:01.500390",
"doctype": "DocType",
"editable_grid": 1,
"engine": "InnoDB",
"field_order": [
"cost_center",
"percentage_allocation"
],
"fields": [
{
"fieldname": "cost_center",
"fieldtype": "Link",
"in_list_view": 1,
"label": "Cost Center",
"options": "Cost Center",
"reqd": 1
},
{
"fieldname": "percentage_allocation",
"fieldtype": "Float",
"in_list_view": 1,
"label": "Percentage Allocation",
"reqd": 1
}
],
"istable": 1,
"links": [],
"modified": "2020-03-19 12:54:43.674655",
"modified_by": "Administrator",
"module": "Accounts",
"name": "Distributed Cost Center",
"owner": "Administrator",
"permissions": [],
"quick_entry": 1,
"sort_field": "modified",
"sort_order": "DESC",
"track_changes": 1
}

View File

@ -0,0 +1,10 @@
# -*- coding: utf-8 -*-
# Copyright (c) 2020, Frappe Technologies Pvt. Ltd. and contributors
# For license information, please see license.txt
from __future__ import unicode_literals
# import frappe
from frappe.model.document import Document
class DistributedCostCenter(Document):
pass

View File

@ -191,6 +191,7 @@
{ {
"fieldname": "total_debit", "fieldname": "total_debit",
"fieldtype": "Currency", "fieldtype": "Currency",
"in_list_view": 1,
"label": "Total Debit", "label": "Total Debit",
"no_copy": 1, "no_copy": 1,
"oldfieldname": "total_debit", "oldfieldname": "total_debit",
@ -252,7 +253,6 @@
"fieldname": "total_amount", "fieldname": "total_amount",
"fieldtype": "Currency", "fieldtype": "Currency",
"hidden": 1, "hidden": 1,
"in_list_view": 1,
"label": "Total Amount", "label": "Total Amount",
"no_copy": 1, "no_copy": 1,
"options": "total_amount_currency", "options": "total_amount_currency",
@ -503,7 +503,7 @@
"idx": 176, "idx": 176,
"is_submittable": 1, "is_submittable": 1,
"links": [], "links": [],
"modified": "2020-04-29 10:55:28.240916", "modified": "2020-06-02 18:15:46.955697",
"modified_by": "Administrator", "modified_by": "Administrator",
"module": "Accounts", "module": "Accounts",
"name": "Journal Entry", "name": "Journal Entry",

View File

@ -18,6 +18,7 @@
"accounting_dimensions_section", "accounting_dimensions_section",
"cost_center", "cost_center",
"dimension_col_break", "dimension_col_break",
"project",
"currency_section", "currency_section",
"account_currency", "account_currency",
"column_break_10", "column_break_10",
@ -32,7 +33,6 @@
"reference_type", "reference_type",
"reference_name", "reference_name",
"reference_due_date", "reference_due_date",
"project",
"col_break3", "col_break3",
"is_advance", "is_advance",
"user_remark", "user_remark",
@ -273,7 +273,7 @@
"idx": 1, "idx": 1,
"istable": 1, "istable": 1,
"links": [], "links": [],
"modified": "2020-04-25 01:47:49.060128", "modified": "2020-06-18 14:06:54.833738",
"modified_by": "Administrator", "modified_by": "Administrator",
"module": "Accounts", "module": "Accounts",
"name": "Journal Entry Account", "name": "Journal Entry Account",

View File

@ -11,21 +11,9 @@ frappe.ui.form.on('Opening Invoice Creation Tool', {
}; };
}); });
frm.set_query('cost_center', 'invoices', function(doc, cdt, cdn) { if (frm.doc.company) {
return { frm.trigger('setup_company_filters');
filters: { }
'company': doc.company
}
};
});
frm.set_query('cost_center', function(doc) {
return {
filters: {
'company': doc.company
}
};
});
}, },
refresh: function(frm) { refresh: function(frm) {
@ -51,19 +39,50 @@ frappe.ui.form.on('Opening Invoice Creation Tool', {
}); });
}, },
company: function(frm) { setup_company_filters: function(frm) {
frappe.call({ frm.set_query('cost_center', 'invoices', function(doc, cdt, cdn) {
method: 'erpnext.accounts.doctype.opening_invoice_creation_tool.opening_invoice_creation_tool.get_temporary_opening_account', return {
args: { filters: {
company: frm.doc.company 'company': doc.company
}, }
callback: (r) => { };
if (r.message) { });
frm.doc.__onload.temporary_opening_account = r.message;
frm.trigger('update_invoice_table'); frm.set_query('cost_center', function(doc) {
return {
filters: {
'company': doc.company
}
};
});
frm.set_query('temporary_opening_account', 'invoices', function(doc, cdt, cdn) {
return {
filters: {
'company': doc.company
} }
} }
}) });
},
company: function(frm) {
if (frm.doc.company) {
frm.trigger('setup_company_filters');
frappe.call({
method: 'erpnext.accounts.doctype.opening_invoice_creation_tool.opening_invoice_creation_tool.get_temporary_opening_account',
args: {
company: frm.doc.company
},
callback: (r) => {
if (r.message) {
frm.doc.__onload.temporary_opening_account = r.message;
frm.trigger('update_invoice_table');
}
}
})
}
}, },
invoice_type: function(frm) { invoice_type: function(frm) {

View File

@ -319,7 +319,7 @@ class PaymentEntry(AccountsController):
invoice_payment_amount_map.setdefault(key, 0.0) invoice_payment_amount_map.setdefault(key, 0.0)
invoice_payment_amount_map[key] += reference.allocated_amount invoice_payment_amount_map[key] += reference.allocated_amount
if not invoice_paid_amount_map.get(reference.reference_name): if not invoice_paid_amount_map.get(key):
payment_schedule = frappe.get_all('Payment Schedule', filters={'parent': reference.reference_name}, payment_schedule = frappe.get_all('Payment Schedule', filters={'parent': reference.reference_name},
fields=['paid_amount', 'payment_amount', 'payment_term']) fields=['paid_amount', 'payment_amount', 'payment_term'])
for term in payment_schedule: for term in payment_schedule:
@ -332,12 +332,14 @@ class PaymentEntry(AccountsController):
frappe.db.sql(""" UPDATE `tabPayment Schedule` SET paid_amount = `paid_amount` - %s frappe.db.sql(""" UPDATE `tabPayment Schedule` SET paid_amount = `paid_amount` - %s
WHERE parent = %s and payment_term = %s""", (amount, key[1], key[0])) WHERE parent = %s and payment_term = %s""", (amount, key[1], key[0]))
else: else:
outstanding = invoice_paid_amount_map.get(key)['outstanding'] outstanding = flt(invoice_paid_amount_map.get(key, {}).get('outstanding'))
if amount > outstanding: if amount > outstanding:
frappe.throw(_('Cannot allocate more than {0} against payment term {1}').format(outstanding, key[0])) frappe.throw(_('Cannot allocate more than {0} against payment term {1}').format(outstanding, key[0]))
frappe.db.sql(""" UPDATE `tabPayment Schedule` SET paid_amount = `paid_amount` + %s if amount and outstanding:
WHERE parent = %s and payment_term = %s""", (amount, key[1], key[0])) frappe.db.sql(""" UPDATE `tabPayment Schedule` SET paid_amount = `paid_amount` + %s
WHERE parent = %s and payment_term = %s""", (amount, key[1], key[0]))
def set_status(self): def set_status(self):
if self.docstatus == 2: if self.docstatus == 2:
@ -451,6 +453,8 @@ class PaymentEntry(AccountsController):
frappe.throw(_("Reference No and Reference Date is mandatory for Bank transaction")) frappe.throw(_("Reference No and Reference Date is mandatory for Bank transaction"))
def set_remarks(self): def set_remarks(self):
if self.remarks: return
if self.payment_type=="Internal Transfer": if self.payment_type=="Internal Transfer":
remarks = [_("Amount {0} {1} transferred from {2} to {3}") remarks = [_("Amount {0} {1} transferred from {2} to {3}")
.format(self.paid_from_account_currency, self.paid_amount, self.paid_from, self.paid_to)] .format(self.paid_from_account_currency, self.paid_amount, self.paid_from, self.paid_to)]
@ -1091,17 +1095,20 @@ def get_payment_entry(dt, dn, party_amount=None, bank_account=None, bank_amount=
def get_reference_as_per_payment_terms(payment_schedule, dt, dn, doc, grand_total, outstanding_amount): def get_reference_as_per_payment_terms(payment_schedule, dt, dn, doc, grand_total, outstanding_amount):
references = [] references = []
for payment_term in payment_schedule: for payment_term in payment_schedule:
references.append({ payment_term_outstanding = flt(payment_term.payment_amount - payment_term.paid_amount,
'reference_doctype': dt,
'reference_name': dn,
'bill_no': doc.get('bill_no'),
'due_date': doc.get('due_date'),
'total_amount': grand_total,
'outstanding_amount': outstanding_amount,
'payment_term': payment_term.payment_term,
'allocated_amount': flt(payment_term.payment_amount - payment_term.paid_amount,
payment_term.precision('payment_amount')) payment_term.precision('payment_amount'))
})
if payment_term_outstanding:
references.append({
'reference_doctype': dt,
'reference_name': dn,
'bill_no': doc.get('bill_no'),
'due_date': doc.get('due_date'),
'total_amount': grand_total,
'outstanding_amount': outstanding_amount,
'payment_term': payment_term.payment_term,
'allocated_amount': payment_term_outstanding
})
return references return references

View File

@ -349,9 +349,10 @@
"read_only": 1 "read_only": 1
} }
], ],
"in_create": 1,
"is_submittable": 1, "is_submittable": 1,
"links": [], "links": [],
"modified": "2020-05-08 10:23:02.815237", "modified": "2020-05-29 17:38:49.392713",
"modified_by": "Administrator", "modified_by": "Administrator",
"module": "Accounts", "module": "Accounts",
"name": "Payment Request", "name": "Payment Request",

View File

@ -69,7 +69,7 @@ class PaymentRequest(Document):
elif self.payment_request_type == 'Inward': elif self.payment_request_type == 'Inward':
self.db_set('status', 'Requested') self.db_set('status', 'Requested')
send_mail = self.payment_gateway_validation() send_mail = self.payment_gateway_validation() if self.payment_gateway else None
ref_doc = frappe.get_doc(self.reference_doctype, self.reference_name) ref_doc = frappe.get_doc(self.reference_doctype, self.reference_name)
if (hasattr(ref_doc, "order_type") and getattr(ref_doc, "order_type") == "Shopping Cart") \ if (hasattr(ref_doc, "order_type") and getattr(ref_doc, "order_type") == "Shopping Cart") \

View File

@ -386,6 +386,50 @@ class TestPricingRule(unittest.TestCase):
self.assertEqual(so.items[1].is_free_item, 1) self.assertEqual(so.items[1].is_free_item, 1)
self.assertEqual(so.items[1].item_code, "_Test Item 2") self.assertEqual(so.items[1].item_code, "_Test Item 2")
def test_cumulative_pricing_rule(self):
frappe.delete_doc_if_exists('Pricing Rule', '_Test Cumulative Pricing Rule')
test_record = {
"doctype": "Pricing Rule",
"title": "_Test Cumulative Pricing Rule",
"apply_on": "Item Code",
"currency": "USD",
"items": [{
"item_code": "_Test Item",
}],
"is_cumulative": 1,
"selling": 1,
"applicable_for": "Customer",
"customer": "_Test Customer",
"rate_or_discount": "Discount Percentage",
"rate": 0,
"min_amt": 0,
"max_amt": 10000,
"discount_percentage": 17.5,
"price_or_product_discount": "Price",
"company": "_Test Company",
"valid_from": frappe.utils.nowdate(),
"valid_upto": frappe.utils.nowdate()
}
frappe.get_doc(test_record.copy()).insert()
args = frappe._dict({
"item_code": "_Test Item",
"company": "_Test Company",
"price_list": "_Test Price List",
"currency": "_Test Currency",
"doctype": "Sales Invoice",
"conversion_rate": 1,
"price_list_currency": "_Test Currency",
"plc_conversion_rate": 1,
"order_type": "Sales",
"customer": "_Test Customer",
"name": None,
"transaction_date": frappe.utils.nowdate()
})
details = get_item_details(args)
self.assertTrue(details)
def make_pricing_rule(**args): def make_pricing_rule(**args):
args = frappe._dict(args) args = frappe._dict(args)

View File

@ -366,8 +366,7 @@ def get_qty_amount_data_for_cumulative(pr_doc, doc, items=[]):
sum_qty, sum_amt = [0, 0] sum_qty, sum_amt = [0, 0]
doctype = doc.get('parenttype') or doc.doctype doctype = doc.get('parenttype') or doc.doctype
date_field = ('transaction_date' date_field = 'transaction_date' if frappe.get_meta(doctype).has_field('transaction_date') else 'posting_date'
if doc.get('transaction_date') else 'posting_date')
child_doctype = '{0} Item'.format(doctype) child_doctype = '{0} Item'.format(doctype)
apply_on = frappe.scrub(pr_doc.get('apply_on')) apply_on = frappe.scrub(pr_doc.get('apply_on'))

View File

@ -398,7 +398,7 @@
{ {
"allow_on_submit": 1, "allow_on_submit": 1,
"fieldname": "po_no", "fieldname": "po_no",
"fieldtype": "Data", "fieldtype": "Small Text",
"label": "Customer's Purchase Order", "label": "Customer's Purchase Order",
"no_copy": 1, "no_copy": 1,
"print_hide": 1 "print_hide": 1
@ -1579,7 +1579,7 @@
"idx": 181, "idx": 181,
"is_submittable": 1, "is_submittable": 1,
"links": [], "links": [],
"modified": "2020-04-29 13:37:09.355300", "modified": "2020-05-19 17:00:57.208696",
"modified_by": "Administrator", "modified_by": "Administrator",
"module": "Accounts", "module": "Accounts",
"name": "Sales Invoice", "name": "Sales Invoice",

View File

@ -582,14 +582,14 @@ class SalesInvoice(SellingController):
def validate_item_code(self): def validate_item_code(self):
for d in self.get('items'): for d in self.get('items'):
if not d.item_code: if not d.item_code and self.is_opening == "No":
msgprint(_("Item Code required at Row No {0}").format(d.idx), raise_exception=True) msgprint(_("Item Code required at Row No {0}").format(d.idx), raise_exception=True)
def validate_warehouse(self): def validate_warehouse(self):
super(SalesInvoice, self).validate_warehouse() super(SalesInvoice, self).validate_warehouse()
for d in self.get_item_list(): for d in self.get_item_list():
if not d.warehouse and frappe.get_cached_value("Item", d.item_code, "is_stock_item"): if not d.warehouse and d.item_code and frappe.get_cached_value("Item", d.item_code, "is_stock_item"):
frappe.throw(_("Warehouse required for stock Item {0}").format(d.item_code)) frappe.throw(_("Warehouse required for stock Item {0}").format(d.item_code))
def validate_delivery_note(self): def validate_delivery_note(self):
@ -1450,11 +1450,17 @@ def get_inter_company_details(doc, doctype):
parties = frappe.db.get_all("Supplier", fields=["name"], filters={"disabled": 0, "is_internal_supplier": 1, "represents_company": doc.company}) parties = frappe.db.get_all("Supplier", fields=["name"], filters={"disabled": 0, "is_internal_supplier": 1, "represents_company": doc.company})
company = frappe.get_cached_value("Customer", doc.customer, "represents_company") company = frappe.get_cached_value("Customer", doc.customer, "represents_company")
if not parties:
frappe.throw(_('No Supplier found for Inter Company Transactions which represents company {0}').format(frappe.bold(doc.company)))
party = get_internal_party(parties, "Supplier", doc) party = get_internal_party(parties, "Supplier", doc)
else: else:
parties = frappe.db.get_all("Customer", fields=["name"], filters={"disabled": 0, "is_internal_customer": 1, "represents_company": doc.company}) parties = frappe.db.get_all("Customer", fields=["name"], filters={"disabled": 0, "is_internal_customer": 1, "represents_company": doc.company})
company = frappe.get_cached_value("Supplier", doc.supplier, "represents_company") company = frappe.get_cached_value("Supplier", doc.supplier, "represents_company")
if not parties:
frappe.throw(_('No Customer found for Inter Company Transactions which represents company {0}').format(frappe.bold(doc.company)))
party = get_internal_party(parties, "Customer", doc) party = get_internal_party(parties, "Customer", doc)
return { return {
@ -1519,14 +1525,22 @@ def make_inter_company_transaction(doctype, source_name, target_doc=None):
def update_details(source_doc, target_doc, source_parent): def update_details(source_doc, target_doc, source_parent):
target_doc.inter_company_invoice_reference = source_doc.name target_doc.inter_company_invoice_reference = source_doc.name
if target_doc.doctype in ["Purchase Invoice", "Purchase Order"]: if target_doc.doctype in ["Purchase Invoice", "Purchase Order"]:
currency = frappe.db.get_value('Supplier', details.get('party'), 'default_currency')
target_doc.company = details.get("company") target_doc.company = details.get("company")
target_doc.supplier = details.get("party") target_doc.supplier = details.get("party")
target_doc.buying_price_list = source_doc.selling_price_list target_doc.buying_price_list = source_doc.selling_price_list
if currency:
target_doc.currency = currency
else: else:
currency = frappe.db.get_value('Customer', details.get('party'), 'default_currency')
target_doc.company = details.get("company") target_doc.company = details.get("company")
target_doc.customer = details.get("party") target_doc.customer = details.get("party")
target_doc.selling_price_list = source_doc.buying_price_list target_doc.selling_price_list = source_doc.buying_price_list
if currency:
target_doc.currency = currency
doclist = get_mapped_doc(doctype, source_name, { doclist = get_mapped_doc(doctype, source_name, {
doctype: { doctype: {
"doctype": target_doctype, "doctype": target_doctype,

View File

@ -1745,53 +1745,6 @@ class TestSalesInvoice(unittest.TestCase):
check_gl_entries(self, si.name, expected_gle, "2019-01-30") check_gl_entries(self, si.name, expected_gle, "2019-01-30")
def test_deferred_error_email(self):
deferred_account = create_account(account_name="Deferred Revenue",
parent_account="Current Liabilities - _TC", company="_Test Company")
item = create_item("_Test Item for Deferred Accounting")
item.enable_deferred_revenue = 1
item.deferred_revenue_account = deferred_account
item.no_of_months = 12
item.save()
si = create_sales_invoice(item=item.name, posting_date="2019-01-10", do_not_submit=True)
si.items[0].enable_deferred_revenue = 1
si.items[0].service_start_date = "2019-01-10"
si.items[0].service_end_date = "2019-03-15"
si.items[0].deferred_revenue_account = deferred_account
si.save()
si.submit()
from erpnext.accounts.deferred_revenue import convert_deferred_revenue_to_income
acc_settings = frappe.get_doc('Accounts Settings', 'Accounts Settings')
acc_settings.acc_frozen_upto = '2019-01-31'
acc_settings.save()
pda = frappe.get_doc(dict(
doctype='Process Deferred Accounting',
posting_date=nowdate(),
start_date="2019-01-01",
end_date="2019-03-31",
type="Income",
company="_Test Company"
))
pda.insert()
pda.submit()
email = frappe.db.sql(""" select name from `tabEmail Queue`
where message like %(txt)s """, {
'txt': "%%%s%%" % "Error while processing deferred accounting for {0}".format(pda.name)
})
self.assertTrue(email)
acc_settings.load_from_db()
acc_settings.acc_frozen_upto = None
acc_settings.save()
def test_inter_company_transaction(self): def test_inter_company_transaction(self):
if not frappe.db.exists("Customer", "_Test Internal Customer"): if not frappe.db.exists("Customer", "_Test Internal Customer"):

View File

@ -45,7 +45,9 @@ class ShippingRule(Document):
shipping_amount = 0.0 shipping_amount = 0.0
by_value = False by_value = False
self.validate_countries(doc) if doc.get_shipping_address():
# validate country only if there is address
self.validate_countries(doc)
if self.calculate_based_on == 'Net Total': if self.calculate_based_on == 'Net Total':
value = doc.base_net_total value = doc.base_net_total

View File

@ -180,7 +180,7 @@ def get_advance_vouchers(suppliers, fiscal_year=None, company=None, from_date=No
if company: if company:
condition += "and company =%s" % (company) condition += "and company =%s" % (company)
if from_date and to_date: if from_date and to_date:
condition += "and posting_date between %s and %s" % (company, from_date, to_date) condition += "and posting_date between %s and %s" % (from_date, to_date)
## Appending the same supplier again if length of suppliers list is 1 ## Appending the same supplier again if length of suppliers list is 1
## since tuple of single element list contains None, For example ('Test Supplier 1', ) ## since tuple of single element list contains None, For example ('Test Supplier 1', )

View File

@ -0,0 +1,51 @@
{
"allow_roles": [
{
"role": "Accounts Manager"
},
{
"role": "Accounts User"
}
],
"creation": "2020-05-13 19:03:32.564049",
"docstatus": 0,
"doctype": "Module Onboarding",
"documentation_url": "https://docs.erpnext.com/docs/user/manual/en/accounts",
"idx": 0,
"is_complete": 0,
"modified": "2020-05-14 22:11:06.475938",
"modified_by": "Administrator",
"module": "Accounts",
"name": "Accounts",
"owner": "Administrator",
"steps": [
{
"step": "Chart Of Accounts"
},
{
"step": "Setup Taxes"
},
{
"step": "Create a Product"
},
{
"step": "Create a Supplier"
},
{
"step": "Create Your First Purchase Invoice"
},
{
"step": "Create a Customer"
},
{
"step": "Create Your First Sales Invoice"
},
{
"step": "Configure Account Settings"
}
],
"subtitle": "Accounts, invoices and taxation.",
"success_message": "The Accounts module is now set up!",
"title": "Let's Setup Your Accounts and Taxes.",
"user_can_dismiss": 1
}

View File

@ -0,0 +1,20 @@
{
"action": "Go to Page",
"creation": "2020-05-13 19:58:20.928127",
"docstatus": 0,
"doctype": "Onboarding Step",
"idx": 0,
"is_complete": 0,
"is_mandatory": 0,
"is_single": 0,
"is_skipped": 0,
"modified": "2020-05-14 17:40:28.410447",
"modified_by": "Administrator",
"name": "Chart Of Accounts",
"owner": "Administrator",
"path": "Tree/Account",
"reference_document": "Account",
"show_full_form": 0,
"title": "Review Chart Of Accounts",
"validate_action": 0
}

View File

@ -0,0 +1,19 @@
{
"action": "Create Entry",
"creation": "2020-05-14 17:53:00.876946",
"docstatus": 0,
"doctype": "Onboarding Step",
"idx": 0,
"is_complete": 0,
"is_mandatory": 0,
"is_single": 1,
"is_skipped": 0,
"modified": "2020-05-14 18:06:25.212923",
"modified_by": "Administrator",
"name": "Configure Account Settings",
"owner": "Administrator",
"reference_document": "Accounts Settings",
"show_full_form": 1,
"title": "Configure Account Settings",
"validate_action": 1
}

View File

@ -0,0 +1,19 @@
{
"action": "Create Entry",
"creation": "2020-05-14 17:46:41.831517",
"docstatus": 0,
"doctype": "Onboarding Step",
"idx": 0,
"is_complete": 0,
"is_mandatory": 0,
"is_single": 0,
"is_skipped": 0,
"modified": "2020-05-14 17:46:41.831517",
"modified_by": "Administrator",
"name": "Create a Customer",
"owner": "Administrator",
"reference_document": "Customer",
"show_full_form": 0,
"title": "Create a Customer",
"validate_action": 1
}

View File

@ -0,0 +1,19 @@
{
"action": "Create Entry",
"creation": "2020-05-14 17:45:28.554605",
"docstatus": 0,
"doctype": "Onboarding Step",
"idx": 0,
"is_complete": 0,
"is_mandatory": 0,
"is_single": 0,
"is_skipped": 0,
"modified": "2020-05-14 17:45:28.554605",
"modified_by": "Administrator",
"name": "Create a Product",
"owner": "Administrator",
"reference_document": "Item",
"show_full_form": 0,
"title": "Create a Product",
"validate_action": 1
}

View File

@ -0,0 +1,19 @@
{
"action": "Create Entry",
"creation": "2020-05-14 22:09:10.043554",
"docstatus": 0,
"doctype": "Onboarding Step",
"idx": 0,
"is_complete": 0,
"is_mandatory": 0,
"is_single": 0,
"is_skipped": 0,
"modified": "2020-05-14 22:09:10.043554",
"modified_by": "Administrator",
"name": "Create a Supplier",
"owner": "Administrator",
"reference_document": "Supplier",
"show_full_form": 0,
"title": "Create a Supplier",
"validate_action": 1
}

View File

@ -0,0 +1,19 @@
{
"action": "Create Entry",
"creation": "2020-05-14 22:10:07.049704",
"docstatus": 0,
"doctype": "Onboarding Step",
"idx": 0,
"is_complete": 0,
"is_mandatory": 0,
"is_single": 0,
"is_skipped": 0,
"modified": "2020-05-14 22:10:07.049704",
"modified_by": "Administrator",
"name": "Create Your First Purchase Invoice",
"owner": "Administrator",
"reference_document": "Purchase Invoice",
"show_full_form": 1,
"title": "Create Your First Purchase Invoice ",
"validate_action": 1
}

View File

@ -0,0 +1,19 @@
{
"action": "Create Entry",
"creation": "2020-05-14 17:48:21.019019",
"docstatus": 0,
"doctype": "Onboarding Step",
"idx": 0,
"is_complete": 0,
"is_mandatory": 0,
"is_single": 0,
"is_skipped": 0,
"modified": "2020-05-14 17:48:21.019019",
"modified_by": "Administrator",
"name": "Create Your First Sales Invoice",
"owner": "Administrator",
"reference_document": "Sales Invoice",
"show_full_form": 1,
"title": "Create Your First Sales Invoice ",
"validate_action": 1
}

View File

@ -0,0 +1,19 @@
{
"action": "Create Entry",
"creation": "2020-05-13 19:29:43.844463",
"docstatus": 0,
"doctype": "Onboarding Step",
"idx": 0,
"is_complete": 0,
"is_mandatory": 0,
"is_single": 0,
"is_skipped": 0,
"modified": "2020-05-14 17:40:16.014413",
"modified_by": "Administrator",
"name": "Setup Taxes",
"owner": "Administrator",
"reference_document": "Sales Taxes and Charges Template",
"show_full_form": 1,
"title": "Lets create a Tax Template for Sales ",
"validate_action": 0
}

View File

@ -602,10 +602,14 @@ def get_party_shipping_address(doctype, name):
else: else:
return '' return ''
def get_partywise_advanced_payment_amount(party_type, posting_date = None, company=None): def get_partywise_advanced_payment_amount(party_type, posting_date = None, future_payment=0, company=None):
cond = "1=1" cond = "1=1"
if posting_date: if posting_date:
cond = "posting_date <= '{0}'".format(posting_date) if future_payment:
cond = "posting_date <= '{0}' OR DATE(creation) <= '{0}' """.format(posting_date)
else:
cond = "posting_date <= '{0}'".format(posting_date)
if company: if company:
cond += "and company = '{0}'".format(company) cond += "and company = '{0}'".format(company)

View File

@ -135,12 +135,5 @@ frappe.query_reports["Accounts Payable"] = {
} }
} }
erpnext.dimension_filters.forEach((dimension) => { erpnext.utils.add_dimensions('Accounts Payable', 9);
frappe.query_reports["Accounts Payable"].filters.splice(9, 0 ,{
"fieldname": dimension["fieldname"],
"label": __(dimension["label"]),
"fieldtype": "Link",
"options": dimension["document_type"]
});
});

View File

@ -104,12 +104,5 @@ frappe.query_reports["Accounts Payable Summary"] = {
} }
} }
erpnext.dimension_filters.forEach((dimension) => { erpnext.utils.add_dimensions('Accounts Payable Summary', 9);
frappe.query_reports["Accounts Payable Summary"].filters.splice(9, 0 ,{
"fieldname": dimension["fieldname"],
"label": __(dimension["label"]),
"fieldtype": "Link",
"options": dimension["document_type"]
});
});

View File

@ -199,12 +199,5 @@ frappe.query_reports["Accounts Receivable"] = {
} }
} }
erpnext.dimension_filters.forEach((dimension) => { erpnext.utils.add_dimensions('Accounts Receivable', 9);
frappe.query_reports["Accounts Receivable"].filters.splice(9, 0 ,{
"fieldname": dimension["fieldname"],
"label": __(dimension["label"]),
"fieldtype": "Link",
"options": dimension["document_type"]
});
});

View File

@ -169,9 +169,11 @@ class ReceivablePayableReport(object):
def append_subtotal_row(self, party): def append_subtotal_row(self, party):
sub_total_row = self.total_row_map.get(party) sub_total_row = self.total_row_map.get(party)
self.data.append(sub_total_row)
self.data.append({}) if sub_total_row:
self.update_sub_total_row(sub_total_row, 'Total') self.data.append(sub_total_row)
self.data.append({})
self.update_sub_total_row(sub_total_row, 'Total')
def get_voucher_balance(self, gle): def get_voucher_balance(self, gle):
if self.filters.get("sales_person"): if self.filters.get("sales_person"):
@ -232,7 +234,8 @@ class ReceivablePayableReport(object):
if self.filters.get('group_by_party'): if self.filters.get('group_by_party'):
self.append_subtotal_row(self.previous_party) self.append_subtotal_row(self.previous_party)
self.data.append(self.total_row_map.get('Total')) if self.data:
self.data.append(self.total_row_map.get('Total'))
def append_row(self, row): def append_row(self, row):
self.allocate_future_payments(row) self.allocate_future_payments(row)
@ -534,7 +537,7 @@ class ReceivablePayableReport(object):
def get_ageing_data(self, entry_date, row): def get_ageing_data(self, entry_date, row):
# [0-30, 30-60, 60-90, 90-120, 120-above] # [0-30, 30-60, 60-90, 90-120, 120-above]
row.range1 = row.range2 = row.range3 = row.range4 = range5 = 0.0 row.range1 = row.range2 = row.range3 = row.range4 = row.range5 = 0.0
if not (self.age_as_on and entry_date): if not (self.age_as_on and entry_date):
return return
@ -546,7 +549,7 @@ class ReceivablePayableReport(object):
self.filters.range1, self.filters.range2, self.filters.range3, self.filters.range4 = 30, 60, 90, 120 self.filters.range1, self.filters.range2, self.filters.range3, self.filters.range4 = 30, 60, 90, 120
for i, days in enumerate([self.filters.range1, self.filters.range2, self.filters.range3, self.filters.range4]): for i, days in enumerate([self.filters.range1, self.filters.range2, self.filters.range3, self.filters.range4]):
if row.age <= days: if cint(row.age) <= cint(days):
index = i index = i
break break
@ -559,6 +562,14 @@ class ReceivablePayableReport(object):
conditions, values = self.prepare_conditions() conditions, values = self.prepare_conditions()
order_by = self.get_order_by_condition() order_by = self.get_order_by_condition()
if self.filters.show_future_payments:
values.insert(2, self.filters.report_date)
date_condition = """AND (posting_date <= %s
OR (against_voucher IS NULL AND DATE(creation) <= %s))"""
else:
date_condition = "AND posting_date <=%s"
if self.filters.get(scrub(self.party_type)): if self.filters.get(scrub(self.party_type)):
select_fields = "debit_in_account_currency as debit, credit_in_account_currency as credit" select_fields = "debit_in_account_currency as debit, credit_in_account_currency as credit"
else: else:
@ -574,9 +585,8 @@ class ReceivablePayableReport(object):
docstatus < 2 docstatus < 2
and party_type=%s and party_type=%s
and (party is not null and party != '') and (party is not null and party != '')
and posting_date <= %s {1} {2} {3}"""
{1} {2}""" .format(select_fields, date_condition, conditions, order_by), values, as_dict=True)
.format(select_fields, conditions, order_by), values, as_dict=True)
def get_sales_invoices_or_customers_based_on_sales_person(self): def get_sales_invoices_or_customers_based_on_sales_person(self):
if self.filters.get("sales_person"): if self.filters.get("sales_person"):

View File

@ -111,7 +111,12 @@ frappe.query_reports["Accounts Receivable Summary"] = {
"fieldname":"based_on_payment_terms", "fieldname":"based_on_payment_terms",
"label": __("Based On Payment Terms"), "label": __("Based On Payment Terms"),
"fieldtype": "Check", "fieldtype": "Check",
} },
{
"fieldname":"show_future_payments",
"label": __("Show Future Payments"),
"fieldtype": "Check",
},
], ],
onload: function(report) { onload: function(report) {
@ -122,11 +127,4 @@ frappe.query_reports["Accounts Receivable Summary"] = {
} }
} }
erpnext.dimension_filters.forEach((dimension) => { erpnext.utils.add_dimensions('Accounts Receivable Summary', 9);
frappe.query_reports["Accounts Receivable Summary"].filters.splice(9, 0 ,{
"fieldname": dimension["fieldname"],
"label": __(dimension["label"]),
"fieldtype": "Link",
"options": dimension["document_type"]
});
});

View File

@ -33,7 +33,7 @@ class AccountsReceivableSummary(ReceivablePayableReport):
self.get_party_total(args) self.get_party_total(args)
party_advance_amount = get_partywise_advanced_payment_amount(self.party_type, party_advance_amount = get_partywise_advanced_payment_amount(self.party_type,
self.filters.report_date, self.filters.company) or {} self.filters.report_date, self.filters.show_future_payments, self.filters.company) or {}
for party, party_dict in iteritems(self.party_total): for party, party_dict in iteritems(self.party_total):
if party_dict.outstanding == 0: if party_dict.outstanding == 0:

View File

@ -93,7 +93,7 @@ def get_assets(filters):
sum(results.depreciation_eliminated_during_the_period) as depreciation_eliminated_during_the_period, sum(results.depreciation_eliminated_during_the_period) as depreciation_eliminated_during_the_period,
sum(results.depreciation_amount_during_the_period) as depreciation_amount_during_the_period sum(results.depreciation_amount_during_the_period) as depreciation_amount_during_the_period
from (SELECT a.asset_category, from (SELECT a.asset_category,
ifnull(sum(case when ds.schedule_date < %(from_date)s then ifnull(sum(case when ds.schedule_date < %(from_date)s and (ifnull(a.disposal_date, 0) = 0 or a.disposal_date >= %(from_date)s) then
ds.depreciation_amount ds.depreciation_amount
else else
0 0
@ -111,13 +111,11 @@ def get_assets(filters):
0 0
end), 0) as depreciation_amount_during_the_period end), 0) as depreciation_amount_during_the_period
from `tabAsset` a, `tabDepreciation Schedule` ds from `tabAsset` a, `tabDepreciation Schedule` ds
where a.docstatus=1 and a.company=%(company)s and a.purchase_date <= %(to_date)s and a.name = ds.parent where a.docstatus=1 and a.company=%(company)s and a.purchase_date <= %(to_date)s and a.name = ds.parent and ifnull(ds.journal_entry, '') != ''
group by a.asset_category group by a.asset_category
union union
SELECT a.asset_category, SELECT a.asset_category,
ifnull(sum(case when ifnull(a.disposal_date, 0) != 0 ifnull(sum(case when ifnull(a.disposal_date, 0) != 0 and (a.disposal_date < %(from_date)s or a.disposal_date > %(to_date)s) then
and (a.disposal_date < %(from_date)s or a.disposal_date > %(to_date)s)
then
0 0
else else
a.opening_accumulated_depreciation a.opening_accumulated_depreciation

View File

@ -4,6 +4,8 @@
frappe.require("assets/erpnext/js/financial_statements.js", function() { frappe.require("assets/erpnext/js/financial_statements.js", function() {
frappe.query_reports["Balance Sheet"] = $.extend({}, erpnext.financial_statements); frappe.query_reports["Balance Sheet"] = $.extend({}, erpnext.financial_statements);
erpnext.utils.add_dimensions('Balance Sheet', 10);
frappe.query_reports["Balance Sheet"]["filters"].push({ frappe.query_reports["Balance Sheet"]["filters"].push({
"fieldname": "accumulated_values", "fieldname": "accumulated_values",
"label": __("Accumulated Values"), "label": __("Accumulated Values"),

View File

@ -29,41 +29,76 @@ def execute(filters=None):
for dimension in dimensions: for dimension in dimensions:
dimension_items = cam_map.get(dimension) dimension_items = cam_map.get(dimension)
if dimension_items: if dimension_items:
for account, monthwise_data in iteritems(dimension_items): data = get_final_data(dimension, dimension_items, filters, period_month_ranges, data, 0)
row = [dimension, account] else:
totals = [0, 0, 0] DCC_allocation = frappe.db.sql('''SELECT parent, sum(percentage_allocation) as percentage_allocation
for year in get_fiscal_years(filters): FROM `tabDistributed Cost Center`
last_total = 0 WHERE cost_center IN %(dimension)s
for relevant_months in period_month_ranges: AND parent NOT IN %(dimension)s
period_data = [0, 0, 0] GROUP BY parent''',{'dimension':[dimension]})
for month in relevant_months: if DCC_allocation:
if monthwise_data.get(year[0]): filters['budget_against_filter'] = [DCC_allocation[0][0]]
month_data = monthwise_data.get(year[0]).get(month, {}) cam_map = get_dimension_account_month_map(filters)
for i, fieldname in enumerate(["target", "actual", "variance"]): dimension_items = cam_map.get(DCC_allocation[0][0])
value = flt(month_data.get(fieldname)) if dimension_items:
period_data[i] += value data = get_final_data(dimension, dimension_items, filters, period_month_ranges, data, DCC_allocation[0][1])
totals[i] += value
period_data[0] += last_total chart = get_chart_data(filters, columns, data)
if filters.get("show_cumulative"): return columns, data, None, chart
last_total = period_data[0] - period_data[1]
period_data[2] = period_data[0] - period_data[1] def get_final_data(dimension, dimension_items, filters, period_month_ranges, data, DCC_allocation):
row += period_data
totals[2] = totals[0] - totals[1]
if filters["period"] != "Yearly":
row += totals
data.append(row)
return columns, data for account, monthwise_data in iteritems(dimension_items):
row = [dimension, account]
totals = [0, 0, 0]
for year in get_fiscal_years(filters):
last_total = 0
for relevant_months in period_month_ranges:
period_data = [0, 0, 0]
for month in relevant_months:
if monthwise_data.get(year[0]):
month_data = monthwise_data.get(year[0]).get(month, {})
for i, fieldname in enumerate(["target", "actual", "variance"]):
value = flt(month_data.get(fieldname))
period_data[i] += value
totals[i] += value
period_data[0] += last_total
if DCC_allocation:
period_data[0] = period_data[0]*(DCC_allocation/100)
period_data[1] = period_data[1]*(DCC_allocation/100)
if(filters.get("show_cumulative")):
last_total = period_data[0] - period_data[1]
period_data[2] = period_data[0] - period_data[1]
row += period_data
totals[2] = totals[0] - totals[1]
if filters["period"] != "Yearly" :
row += totals
data.append(row)
return data
def get_columns(filters): def get_columns(filters):
columns = [ columns = [
_(filters.get("budget_against")) {
+ ":Link/%s:150" % (filters.get("budget_against")), 'label': _(filters.get("budget_against")),
_("Account") + ":Link/Account:150" 'fieldtype': 'Link',
'fieldname': 'budget_against',
'options': filters.get('budget_against'),
'width': 150
},
{
'label': _('Account'),
'fieldname': 'Account',
'fieldtype': 'Link',
'options': 'Account',
'width': 150
}
] ]
group_months = False if filters["period"] == "Monthly" else True group_months = False if filters["period"] == "Monthly" else True
@ -79,7 +114,12 @@ def get_columns(filters):
_("Variance ") + " " + str(year[0]) _("Variance ") + " " + str(year[0])
] ]
for label in labels: for label in labels:
columns.append(label + ":Float:150") columns.append({
'label': label,
'fieldtype': 'Float',
'fieldname': frappe.scrub(label),
'width': 150
})
else: else:
for label in [ for label in [
_("Budget") + " (%s)" + " " + str(year[0]), _("Budget") + " (%s)" + " " + str(year[0]),
@ -95,14 +135,23 @@ def get_columns(filters):
else: else:
label = label % formatdate(from_date, format_string="MMM") label = label % formatdate(from_date, format_string="MMM")
columns.append(label + ":Float:150") columns.append({
'label': label,
'fieldtype': 'Float',
'fieldname': frappe.scrub(label),
'width': 150
})
if filters["period"] != "Yearly": if filters["period"] != "Yearly":
return columns + [ for label in [_("Total Budget"), _("Total Actual"), _("Total Variance")]:
_("Total Budget") + ":Float:150", columns.append({
_("Total Actual") + ":Float:150", 'label': label,
_("Total Variance") + ":Float:150" 'fieldtype': 'Float',
] 'fieldname': frappe.scrub(label),
'width': 150
})
return columns
else: else:
return columns return columns
@ -173,7 +222,7 @@ def get_dimension_target_details(filters):
filters.budget_against, filters.budget_against,
filters.company, filters.company,
] ]
+ filters.get("budget_against_filter") + (filters.get("budget_against_filter") or [])
), as_dict=True) ), as_dict=True)
@ -305,3 +354,49 @@ def get_fiscal_years(filters):
}) })
return fiscal_year return fiscal_year
def get_chart_data(filters, columns, data):
if not data:
return None
labels = []
fiscal_year = get_fiscal_years(filters)
group_months = False if filters["period"] == "Monthly" else True
for year in fiscal_year:
for from_date, to_date in get_period_date_ranges(filters["period"], year[0]):
if filters['period'] == 'Yearly':
labels.append(year[0])
else:
if group_months:
label = formatdate(from_date, format_string="MMM") + "-" \
+ formatdate(to_date, format_string="MMM")
labels.append(label)
else:
label = formatdate(from_date, format_string="MMM")
labels.append(label)
no_of_columns = len(labels)
budget_values, actual_values = [0] * no_of_columns, [0] * no_of_columns
for d in data:
values = d[2:]
index = 0
for i in range(no_of_columns):
budget_values[i] += values[index]
actual_values[i] += values[index+1]
index += 3
return {
'data': {
'labels': labels,
'datasets': [
{'name': 'Budget', 'chartType': 'bar', 'values': budget_values},
{'name': 'Actual Expense', 'chartType': 'bar', 'values': actual_values}
]
}
}

View File

@ -5,6 +5,8 @@ frappe.require("assets/erpnext/js/financial_statements.js", function() {
frappe.query_reports["Cash Flow"] = $.extend({}, frappe.query_reports["Cash Flow"] = $.extend({},
erpnext.financial_statements); erpnext.financial_statements);
erpnext.utils.add_dimensions('Cash Flow', 10);
// The last item in the array is the definition for Presentation Currency // The last item in the array is the definition for Presentation Currency
// filter. It won't be used in cash flow for now so we pop it. Please take // filter. It won't be used in cash flow for now so we pop it. Please take
// of this if you are working here. // of this if you are working here.

View File

@ -33,7 +33,6 @@ frappe.query_reports["Consolidated Financial Statement"] = {
"fieldname":"period_start_date", "fieldname":"period_start_date",
"label": __("Start Date"), "label": __("Start Date"),
"fieldtype": "Date", "fieldtype": "Date",
"default": frappe.datetime.nowdate(),
"hidden": 1, "hidden": 1,
"reqd": 1 "reqd": 1
}, },
@ -41,7 +40,6 @@ frappe.query_reports["Consolidated Financial Statement"] = {
"fieldname":"period_end_date", "fieldname":"period_end_date",
"label": __("End Date"), "label": __("End Date"),
"fieldtype": "Date", "fieldtype": "Date",
"default": frappe.datetime.add_months(frappe.datetime.nowdate(), 12),
"hidden": 1, "hidden": 1,
"reqd": 1 "reqd": 1
}, },
@ -106,5 +104,16 @@ frappe.query_reports["Consolidated Financial Statement"] = {
value = $value.wrap("<p></p>").parent().html(); value = $value.wrap("<p></p>").parent().html();
} }
return value; return value;
},
onload: function() {
let fiscal_year = frappe.defaults.get_user_default("fiscal_year")
frappe.model.with_doc("Fiscal Year", fiscal_year, function(r) {
var fy = frappe.model.get_doc("Fiscal Year", fiscal_year);
frappe.query_report.set_filter_value({
period_start_date: fy.year_start_date,
period_end_date: fy.year_end_date
});
});
} }
} }

View File

@ -19,7 +19,7 @@ from six import itervalues
from erpnext.accounts.doctype.accounting_dimension.accounting_dimension import get_accounting_dimensions, get_dimension_with_children from erpnext.accounts.doctype.accounting_dimension.accounting_dimension import get_accounting_dimensions, get_dimension_with_children
def get_period_list(from_fiscal_year, to_fiscal_year, period_start_date, period_end_date, filter_based_on, periodicity, accumulated_values=False, def get_period_list(from_fiscal_year, to_fiscal_year, period_start_date, period_end_date, filter_based_on, periodicity, accumulated_values=False,
company=None, reset_period_on_fy_change=True): company=None, reset_period_on_fy_change=True, ignore_fiscal_year=False):
"""Get a list of dict {"from_date": from_date, "to_date": to_date, "key": key, "label": label} """Get a list of dict {"from_date": from_date, "to_date": to_date, "key": key, "label": label}
Periodicity can be (Yearly, Quarterly, Monthly)""" Periodicity can be (Yearly, Quarterly, Monthly)"""
@ -56,9 +56,8 @@ def get_period_list(from_fiscal_year, to_fiscal_year, period_start_date, period_
to_date = add_months(start_date, months_to_add) to_date = add_months(start_date, months_to_add)
start_date = to_date start_date = to_date
if to_date == get_first_day(to_date): # Subtract one day from to_date, as it may be first day in next fiscal year or month
# if to_date is the first day, get the last day of previous month to_date = add_days(to_date, -1)
to_date = add_days(to_date, -1)
if to_date <= year_end_date: if to_date <= year_end_date:
# the normal case # the normal case
@ -67,8 +66,9 @@ def get_period_list(from_fiscal_year, to_fiscal_year, period_start_date, period_
# if a fiscal year ends before a 12 month period # if a fiscal year ends before a 12 month period
period.to_date = year_end_date period.to_date = year_end_date
period.to_date_fiscal_year = get_fiscal_year(period.to_date, company=company)[0] if not ignore_fiscal_year:
period.from_date_fiscal_year_start_date = get_fiscal_year(period.from_date, company=company)[1] period.to_date_fiscal_year = get_fiscal_year(period.to_date, company=company)[0]
period.from_date_fiscal_year_start_date = get_fiscal_year(period.from_date, company=company)[1]
period_list.append(period) period_list.append(period)
@ -386,11 +386,43 @@ def set_gl_entries_by_account(
key: value key: value
}) })
distributed_cost_center_query = ""
if filters and filters.get('cost_center'):
distributed_cost_center_query = """
UNION ALL
SELECT posting_date,
account,
debit*(DCC_allocation.percentage_allocation/100) as debit,
credit*(DCC_allocation.percentage_allocation/100) as credit,
is_opening,
fiscal_year,
debit_in_account_currency*(DCC_allocation.percentage_allocation/100) as debit_in_account_currency,
credit_in_account_currency*(DCC_allocation.percentage_allocation/100) as credit_in_account_currency,
account_currency
FROM `tabGL Entry`,
(
SELECT parent, sum(percentage_allocation) as percentage_allocation
FROM `tabDistributed Cost Center`
WHERE cost_center IN %(cost_center)s
AND parent NOT IN %(cost_center)s
AND is_cancelled = 0
GROUP BY parent
) as DCC_allocation
WHERE company=%(company)s
{additional_conditions}
AND posting_date <= %(to_date)s
AND cost_center = DCC_allocation.parent
""".format(additional_conditions=additional_conditions.replace("and cost_center in %(cost_center)s ", ''))
gl_entries = frappe.db.sql("""select posting_date, account, debit, credit, is_opening, fiscal_year, debit_in_account_currency, credit_in_account_currency, account_currency from `tabGL Entry` gl_entries = frappe.db.sql("""select posting_date, account, debit, credit, is_opening, fiscal_year, debit_in_account_currency, credit_in_account_currency, account_currency from `tabGL Entry`
where company=%(company)s where company=%(company)s
{additional_conditions} {additional_conditions}
and posting_date <= %(to_date)s and posting_date <= %(to_date)s
order by account, posting_date""".format(additional_conditions=additional_conditions), gl_filters, as_dict=True) #nosec and is_cancelled = 0
{distributed_cost_center_query}
order by account, posting_date""".format(
additional_conditions=additional_conditions,
distributed_cost_center_query=distributed_cost_center_query), gl_filters, as_dict=True) #nosec
if filters and filters.get('presentation_currency'): if filters and filters.get('presentation_currency'):
convert_to_presentation_currency(gl_entries, get_currency(filters)) convert_to_presentation_currency(gl_entries, get_currency(filters))

View File

@ -164,12 +164,5 @@ frappe.query_reports["General Ledger"] = {
] ]
} }
erpnext.dimension_filters.forEach((dimension) => { erpnext.utils.add_dimensions('General Ledger', 15)
frappe.query_reports["General Ledger"].filters.splice(15, 0 ,{
"fieldname": dimension["fieldname"],
"label": __(dimension["label"]),
"fieldtype": "Link",
"options": dimension["document_type"]
});
});

View File

@ -128,18 +128,53 @@ def get_gl_entries(filters):
filters['company_fb'] = frappe.db.get_value("Company", filters['company_fb'] = frappe.db.get_value("Company",
filters.get("company"), 'default_finance_book') filters.get("company"), 'default_finance_book')
distributed_cost_center_query = ""
if filters and filters.get('cost_center'):
select_fields_with_percentage = """, debit*(DCC_allocation.percentage_allocation/100) as debit, credit*(DCC_allocation.percentage_allocation/100) as credit, debit_in_account_currency*(DCC_allocation.percentage_allocation/100) as debit_in_account_currency,
credit_in_account_currency*(DCC_allocation.percentage_allocation/100) as credit_in_account_currency """
distributed_cost_center_query = """
UNION ALL
SELECT name as gl_entry,
posting_date,
account,
party_type,
party,
voucher_type,
voucher_no,
cost_center, project,
against_voucher_type,
against_voucher,
account_currency,
remarks, against,
is_opening, `tabGL Entry`.creation {select_fields_with_percentage}
FROM `tabGL Entry`,
(
SELECT parent, sum(percentage_allocation) as percentage_allocation
FROM `tabDistributed Cost Center`
WHERE cost_center IN %(cost_center)s
AND parent NOT IN %(cost_center)s
GROUP BY parent
) as DCC_allocation
WHERE company=%(company)s
{conditions}
AND posting_date <= %(to_date)s
AND cost_center = DCC_allocation.parent
""".format(select_fields_with_percentage=select_fields_with_percentage, conditions=get_conditions(filters).replace("and cost_center in %(cost_center)s ", ''))
gl_entries = frappe.db.sql( gl_entries = frappe.db.sql(
""" """
select select
name as gl_entry, posting_date, account, party_type, party, name as gl_entry, posting_date, account, party_type, party,
voucher_type, voucher_no, cost_center, project, voucher_type, voucher_no, cost_center, project,
against_voucher_type, against_voucher, account_currency, against_voucher_type, against_voucher, account_currency,
remarks, against, is_opening {select_fields} remarks, against, is_opening, creation {select_fields}
from `tabGL Entry` from `tabGL Entry`
where company=%(company)s {conditions} where company=%(company)s {conditions}
{distributed_cost_center_query}
{order_by_statement} {order_by_statement}
""".format( """.format(
select_fields=select_fields, conditions=get_conditions(filters), select_fields=select_fields, conditions=get_conditions(filters), distributed_cost_center_query=distributed_cost_center_query,
order_by_statement=order_by_statement order_by_statement=order_by_statement
), ),
filters, as_dict=1) filters, as_dict=1)
@ -296,7 +331,7 @@ def get_accountwise_gle(filters, gl_entries, gle_map):
data[key].debit_in_account_currency += flt(gle.debit_in_account_currency) data[key].debit_in_account_currency += flt(gle.debit_in_account_currency)
data[key].credit_in_account_currency += flt(gle.credit_in_account_currency) data[key].credit_in_account_currency += flt(gle.credit_in_account_currency)
if data[key].against_voucher: if data[key].against_voucher and gle.against_voucher:
data[key].against_voucher += ', ' + gle.against_voucher data[key].against_voucher += ', ' + gle.against_voucher
from_date, to_date = getdate(filters.from_date), getdate(filters.to_date) from_date, to_date = getdate(filters.from_date), getdate(filters.to_date)

View File

@ -4,11 +4,18 @@
frappe.query_reports["Item-wise Purchase Register"] = { frappe.query_reports["Item-wise Purchase Register"] = {
"filters": [ "filters": [
{ {
"fieldname":"date_range", "fieldname":"from_date",
"label": __("Date Range"), "label": __("From Date"),
"fieldtype": "DateRange", "fieldtype": "Date",
"default": [frappe.datetime.add_months(frappe.datetime.get_today(),-1), frappe.datetime.get_today()], "default": frappe.datetime.add_months(frappe.datetime.get_today(), -1),
"reqd": 1 "reqd": 1,
},
{
"fieldname":"to_date",
"label": __("To Date"),
"fieldtype": "Date",
"default": frappe.datetime.get_today(),
"reqd": 1,
}, },
{ {
"fieldname": "item_code", "fieldname": "item_code",

View File

@ -14,7 +14,6 @@ def execute(filters=None):
def _execute(filters=None, additional_table_columns=None, additional_query_columns=None): def _execute(filters=None, additional_table_columns=None, additional_query_columns=None):
if not filters: filters = {} if not filters: filters = {}
filters.update({"from_date": filters.get("date_range")[0], "to_date": filters.get("date_range")[1]})
columns = get_columns(additional_table_columns, filters) columns = get_columns(additional_table_columns, filters)
company_currency = erpnext.get_company_currency(filters.company) company_currency = erpnext.get_company_currency(filters.company)
@ -266,13 +265,6 @@ def get_columns(additional_table_columns, filters):
'fieldtype': 'Currency', 'fieldtype': 'Currency',
'options': 'currency', 'options': 'currency',
'width': 100 'width': 100
},
{
'fieldname': 'currency',
'label': _('Currency'),
'fieldtype': 'Currency',
'width': 80,
'hidden': 1
} }
] ]

View File

@ -4,11 +4,18 @@
frappe.query_reports["Item-wise Sales Register"] = { frappe.query_reports["Item-wise Sales Register"] = {
"filters": [ "filters": [
{ {
"fieldname": "date_range", "fieldname":"from_date",
"label": __("Date Range"), "label": __("From Date"),
"fieldtype": "DateRange", "fieldtype": "Date",
"default": [frappe.datetime.add_months(frappe.datetime.get_today(),-1), frappe.datetime.get_today()], "default": frappe.datetime.add_months(frappe.datetime.get_today(), -1),
"reqd": 1 "reqd": 1,
},
{
"fieldname":"to_date",
"label": __("To Date"),
"fieldtype": "Date",
"default": frappe.datetime.get_today(),
"reqd": 1,
}, },
{ {
"fieldname": "customer", "fieldname": "customer",

View File

@ -14,7 +14,6 @@ def execute(filters=None):
def _execute(filters=None, additional_table_columns=None, additional_query_columns=None): def _execute(filters=None, additional_table_columns=None, additional_query_columns=None):
if not filters: filters = {} if not filters: filters = {}
filters.update({"from_date": filters.get("date_range") and filters.get("date_range")[0], "to_date": filters.get("date_range") and filters.get("date_range")[1]})
columns = get_columns(additional_table_columns, filters) columns = get_columns(additional_table_columns, filters)
company_currency = frappe.get_cached_value('Company', filters.get("company"), "default_currency") company_currency = frappe.get_cached_value('Company', filters.get("company"), "default_currency")
@ -224,7 +223,7 @@ def get_columns(additional_table_columns, filters):
} }
] ]
if filters.get('group_by') != 'Terriotory': if filters.get('group_by') != 'Territory':
columns.extend([ columns.extend([
{ {
'label': _("Territory"), 'label': _("Territory"),
@ -305,13 +304,6 @@ def get_columns(additional_table_columns, filters):
'fieldtype': 'Currency', 'fieldtype': 'Currency',
'options': 'currency', 'options': 'currency',
'width': 100 'width': 100
},
{
'fieldname': 'currency',
'label': _('Currency'),
'fieldtype': 'Currency',
'width': 80,
'hidden': 1
} }
] ]
@ -537,6 +529,13 @@ def get_tax_accounts(item_list, columns, company_currency,
'fieldtype': 'Currency', 'fieldtype': 'Currency',
'options': 'currency', 'options': 'currency',
'width': 100 'width': 100
},
{
'fieldname': 'currency',
'label': _('Currency'),
'fieldtype': 'Currency',
'width': 80,
'hidden': 1
} }
] ]

View File

@ -1,27 +0,0 @@
{
"add_total_row": 1,
"apply_user_permissions": 1,
"creation": "2013-02-21 14:26:44",
"disabled": 0,
"docstatus": 0,
"doctype": "Report",
"idx": 3,
"is_standard": "Yes",
"modified": "2017-11-06 13:04:51.559061",
"modified_by": "Administrator",
"module": "Accounts",
"name": "Ordered Items To Be Billed",
"owner": "Administrator",
"query": "select \n `tabSales Order`.`name` as \"Sales Order:Link/Sales Order:120\",\n `tabSales Order`.`customer` as \"Customer:Link/Customer:120\",\n `tabSales Order`.`customer_name` as \"Customer Name:150\",\n`tabSales Order`.`status` as \"Status\",\n `tabSales Order`.`transaction_date` as \"Date:Date\",\n `tabSales Order`.`project` as \"Project\",\n `tabSales Order Item`.item_code as \"Item:Link/Item:120\",\n `tabSales Order Item`.base_amount as \"Amount:Currency:110\",\n (`tabSales Order Item`.billed_amt * ifnull(`tabSales Order`.conversion_rate, 1)) as \"Billed Amount:Currency:110\",\n (`tabSales Order Item`.base_amount - (`tabSales Order Item`.billed_amt * ifnull(`tabSales Order`.conversion_rate, 1))) as \"Pending Amount:Currency:120\",\n `tabSales Order Item`.item_name as \"Item Name::150\",\n `tabSales Order Item`.description as \"Description::200\",\n `tabSales Order`.`company` as \"Company:Link/Company:\"\nfrom\n `tabSales Order`, `tabSales Order Item`\nwhere\n `tabSales Order Item`.`parent` = `tabSales Order`.`name`\n and `tabSales Order`.docstatus = 1\n and `tabSales Order`.status != \"Closed\"\n and `tabSales Order Item`.amount > 0\n and `tabSales Order Item`.billed_amt < `tabSales Order Item`.amount\norder by `tabSales Order`.transaction_date asc",
"ref_doctype": "Sales Invoice",
"report_name": "Ordered Items To Be Billed",
"report_type": "Script Report",
"roles": [
{
"role": "Accounts Manager"
},
{
"role": "Accounts User"
}
]
}

View File

@ -1,26 +0,0 @@
# Copyright (c) 2013, Frappe Technologies Pvt. Ltd. and contributors
# For license information, please see license.txt
from __future__ import unicode_literals
import frappe
from frappe import _
from erpnext.accounts.report.non_billed_report import get_ordered_to_be_billed_data
def execute(filters=None):
columns = get_column()
args = get_args()
data = get_ordered_to_be_billed_data(args)
return columns, data
def get_column():
return [
_("Sales Order") + ":Link/Sales Order:120", _("Status") + "::120", _("Date") + ":Date:100",
_("Suplier") + ":Link/Customer:120", _("Customer Name") + "::120",
_("Project") + ":Link/Project:120", _("Item Code") + ":Link/Item:120",
_("Amount") + ":Currency:100", _("Billed Amount") + ":Currency:100", _("Pending Amount") + ":Currency:100",
_("Item Name") + "::120", _("Description") + "::120", _("Company") + ":Link/Company:120",
]
def get_args():
return {'doctype': 'Sales Order', 'party': 'customer',
'date': 'transaction_date', 'order': 'transaction_date', 'order_by': 'asc'}

View File

@ -6,6 +6,8 @@ frappe.require("assets/erpnext/js/financial_statements.js", function() {
frappe.query_reports["Profit and Loss Statement"] = $.extend({}, frappe.query_reports["Profit and Loss Statement"] = $.extend({},
erpnext.financial_statements); erpnext.financial_statements);
erpnext.utils.add_dimensions('Profit and Loss Statement', 10);
frappe.query_reports["Profit and Loss Statement"]["filters"].push( frappe.query_reports["Profit and Loss Statement"]["filters"].push(
{ {
"fieldname": "project", "fieldname": "project",

View File

@ -105,6 +105,7 @@ def accumulate_values_into_parents(accounts, accounts_by_name):
def prepare_data(accounts, filters, total_row, parent_children_map, based_on): def prepare_data(accounts, filters, total_row, parent_children_map, based_on):
data = [] data = []
new_accounts = accounts
company_currency = frappe.get_cached_value('Company', filters.get("company"), "default_currency") company_currency = frappe.get_cached_value('Company', filters.get("company"), "default_currency")
for d in accounts: for d in accounts:
@ -118,6 +119,19 @@ def prepare_data(accounts, filters, total_row, parent_children_map, based_on):
"currency": company_currency, "currency": company_currency,
"based_on": based_on "based_on": based_on
} }
if based_on == 'cost_center':
cost_center_doc = frappe.get_doc("Cost Center",d.name)
if not cost_center_doc.enable_distributed_cost_center:
DCC_allocation = frappe.db.sql("""SELECT parent, sum(percentage_allocation) as percentage_allocation
FROM `tabDistributed Cost Center`
WHERE cost_center IN %(cost_center)s
AND parent NOT IN %(cost_center)s
GROUP BY parent""",{'cost_center': [d.name]})
if DCC_allocation:
for account in new_accounts:
if account['name'] == DCC_allocation[0][0]:
for value in value_fields:
d[value] += account[value]*(DCC_allocation[0][1]/100)
for key in value_fields: for key in value_fields:
row[key] = flt(d.get(key, 0.0), 3) row[key] = flt(d.get(key, 0.0), 3)

View File

@ -1,8 +0,0 @@
// Copyright (c) 2016, Frappe Technologies Pvt. Ltd. and contributors
// For license information, please see license.txt
frappe.query_reports["Purchase Order Items To Be Billed"] = {
"filters": [
]
}

View File

@ -1,33 +0,0 @@
{
"add_total_row": 1,
"apply_user_permissions": 1,
"creation": "2013-05-28 15:54:16",
"disabled": 0,
"docstatus": 0,
"doctype": "Report",
"idx": 3,
"is_standard": "Yes",
"modified": "2017-02-24 20:00:24.302988",
"modified_by": "Administrator",
"module": "Accounts",
"name": "Purchase Order Items To Be Billed",
"owner": "Administrator",
"query": "select \n `tabPurchase Order`.`name` as \"Purchase Order:Link/Purchase Order:120\",\n `tabPurchase Order`.`transaction_date` as \"Date:Date:100\",\n\t`tabPurchase Order`.`supplier` as \"Supplier:Link/Supplier:120\",\n\t`tabPurchase Order`.`supplier_name` as \"Supplier Name::150\",\n\t`tabPurchase Order Item`.`project` as \"Project\",\n\t`tabPurchase Order Item`.item_code as \"Item Code:Link/Item:120\",\n\t`tabPurchase Order Item`.base_amount as \"Amount:Currency:100\",\n\t(`tabPurchase Order Item`.billed_amt * ifnull(`tabPurchase Order`.conversion_rate, 1)) as \"Billed Amount:Currency:100\", \n\t(`tabPurchase Order Item`.base_amount - (`tabPurchase Order Item`.billed_amt * ifnull(`tabPurchase Order`.conversion_rate, 1))) as \"Amount to Bill:Currency:100\",\n\t`tabPurchase Order Item`.item_name as \"Item Name::150\",\n\t`tabPurchase Order Item`.description as \"Description::200\",\n\t`tabPurchase Order`.company as \"Company:Link/Company:\"\nfrom\n\t`tabPurchase Order`, `tabPurchase Order Item`\nwhere\n\t`tabPurchase Order Item`.`parent` = `tabPurchase Order`.`name`\n\tand `tabPurchase Order`.docstatus = 1\n\tand `tabPurchase Order`.status != \"Closed\"\n and `tabPurchase Order Item`.amount > 0\n\tand (`tabPurchase Order Item`.billed_amt * ifnull(`tabPurchase Order`.conversion_rate, 1)) < `tabPurchase Order Item`.base_amount\norder by `tabPurchase Order`.transaction_date asc",
"ref_doctype": "Purchase Invoice",
"report_name": "Purchase Order Items To Be Billed",
"report_type": "Script Report",
"roles": [
{
"role": "Accounts User"
},
{
"role": "Purchase User"
},
{
"role": "Auditor"
},
{
"role": "Accounts Manager"
}
]
}

View File

@ -1,26 +0,0 @@
# Copyright (c) 2013, Frappe Technologies Pvt. Ltd. and contributors
# For license information, please see license.txt
from __future__ import unicode_literals
import frappe
from frappe import _
from erpnext.accounts.report.non_billed_report import get_ordered_to_be_billed_data
def execute(filters=None):
columns = get_column()
args = get_args()
data = get_ordered_to_be_billed_data(args)
return columns, data
def get_column():
return [
_("Purchase Order") + ":Link/Purchase Order:120", _("Status") + "::120", _("Date") + ":Date:100",
_("Suplier") + ":Link/Supplier:120", _("Suplier Name") + "::120",
_("Project") + ":Link/Project:120", _("Item Code") + ":Link/Item:120",
_("Amount") + ":Currency:100", _("Billed Amount") + ":Currency:100", _("Amount to Bill") + ":Currency:100",
_("Item Name") + "::120", _("Description") + "::120", _("Company") + ":Link/Company:120",
]
def get_args():
return {'doctype': 'Purchase Order', 'party': 'supplier',
'date': 'transaction_date', 'order': 'transaction_date', 'order_by': 'asc'}

View File

@ -56,11 +56,4 @@ frappe.query_reports["Purchase Register"] = {
] ]
} }
erpnext.dimension_filters.forEach((dimension) => { erpnext.utils.add_dimensions('Purchase Register', 7);
frappe.query_reports["Purchase Register"].filters.splice(7, 0 ,{
"fieldname": dimension["fieldname"],
"label": __(dimension["label"]),
"fieldtype": "Link",
"options": dimension["document_type"]
});
});

View File

@ -68,12 +68,5 @@ frappe.query_reports["Sales Register"] = {
] ]
} }
erpnext.dimension_filters.forEach((dimension) => { erpnext.utils.add_dimensions('Sales Register', 7);
frappe.query_reports["Sales Register"].filters.splice(7, 0 ,{
"fieldname": dimension["fieldname"],
"label": __(dimension["label"]),
"fieldtype": "Link",
"options": dimension["document_type"]
});
});

View File

@ -111,7 +111,7 @@ def get_gle_map(filters):
# {"purchase_invoice": list of dict of all gle created for this invoice} # {"purchase_invoice": list of dict of all gle created for this invoice}
gle_map = {} gle_map = {}
gle = frappe.db.get_all('GL Entry',\ gle = frappe.db.get_all('GL Entry',\
{"voucher_no": ["in", [d.get("name") for d in filters["invoices"]]]}, {"voucher_no": ["in", [d.get("name") for d in filters["invoices"]]], 'is_cancelled': 0},
["fiscal_year", "credit", "debit", "account", "voucher_no", "posting_date"]) ["fiscal_year", "credit", "debit", "account", "voucher_no", "posting_date"])
for d in gle: for d in gle:

View File

@ -102,14 +102,7 @@ frappe.require("assets/erpnext/js/financial_statements.js", function() {
"initial_depth": 3 "initial_depth": 3
} }
erpnext.dimension_filters.forEach((dimension) => { erpnext.utils.add_dimensions('Trial Balance', 6);
frappe.query_reports["Trial Balance"].filters.splice(6, 0 ,{
"fieldname": dimension["fieldname"],
"label": __(dimension["label"]),
"fieldtype": "Link",
"options": dimension["document_type"]
});
});
}); });

View File

@ -71,7 +71,8 @@ def get_data(filters):
opening_balances = get_opening_balances(filters) opening_balances = get_opening_balances(filters)
#add filter inside list so that the query in financial_statements.py doesn't break #add filter inside list so that the query in financial_statements.py doesn't break
filters.project = [filters.project] if filters.project:
filters.project = [filters.project]
set_gl_entries_by_account(filters.company, filters.from_date, set_gl_entries_by_account(filters.company, filters.from_date,
filters.to_date, min_lft, max_rgt, filters, gl_entries_by_account, ignore_closing_entries=not flt(filters.with_period_closing_entry)) filters.to_date, min_lft, max_rgt, filters, gl_entries_by_account, ignore_closing_entries=not flt(filters.with_period_closing_entry))

View File

@ -57,6 +57,9 @@ def get_fiscal_years(transaction_date=None, fiscal_year=None, label="Date", verb
frappe.cache().hset("fiscal_years", company, fiscal_years) frappe.cache().hset("fiscal_years", company, fiscal_years)
if not transaction_date and not fiscal_year:
return fiscal_years
if transaction_date: if transaction_date:
transaction_date = getdate(transaction_date) transaction_date = getdate(transaction_date)
@ -79,6 +82,23 @@ def get_fiscal_years(transaction_date=None, fiscal_year=None, label="Date", verb
if verbose==1: frappe.msgprint(error_msg) if verbose==1: frappe.msgprint(error_msg)
raise FiscalYearError(error_msg) raise FiscalYearError(error_msg)
@frappe.whitelist()
def get_fiscal_year_filter_field(company=None):
field = {
"fieldtype": "Select",
"options": [],
"operator": "Between",
"query_value": True
}
fiscal_years = get_fiscal_years(company=company)
for fiscal_year in fiscal_years:
field["options"].append({
"label": fiscal_year.name,
"value": fiscal_year.name,
"query_value": [fiscal_year.year_start_date.strftime("%Y-%m-%d"), fiscal_year.year_end_date.strftime("%Y-%m-%d")]
})
return field
def validate_fiscal_year(date, fiscal_year, company, label="Date", doc=None): def validate_fiscal_year(date, fiscal_year, company, label="Date", doc=None):
years = [f[0] for f in get_fiscal_years(date, label=_(label), company=company)] years = [f[0] for f in get_fiscal_years(date, label=_(label), company=company)]
if fiscal_year not in years: if fiscal_year not in years:

View File

@ -0,0 +1,179 @@
# Copyright (c) 2020, Frappe Technologies Pvt. Ltd. and Contributors
# License: GNU General Public License v3. See license.txt
import frappe
import json
from frappe.utils import nowdate, add_months, get_date_str
from frappe import _
from erpnext.accounts.dashboard_fixtures import _get_fiscal_year
from erpnext.buying.dashboard_fixtures import get_company_for_dashboards
def get_data():
fiscal_year = _get_fiscal_year(nowdate())
if not fiscal_year:
return frappe._dict()
year_start_date = get_date_str(fiscal_year.get('year_start_date'))
year_end_date = get_date_str(fiscal_year.get('year_end_date'))
return frappe._dict({
"dashboards": get_dashboards(),
"charts": get_charts(fiscal_year, year_start_date, year_end_date),
"number_cards": get_number_cards(fiscal_year, year_start_date, year_end_date),
})
def get_dashboards():
return [{
"name": "Asset",
"dashboard_name": "Asset",
"charts": [
{ "chart": "Asset Value Analytics", "width": "Full" },
{ "chart": "Category-wise Asset Value", "width": "Half" },
{ "chart": "Location-wise Asset Value", "width": "Half" },
],
"cards": [
{"card": "Total Assets"},
{"card": "New Assets (This Year)"},
{"card": "Asset Value"}
]
}]
def get_charts(fiscal_year, year_start_date, year_end_date):
company = get_company_for_dashboards()
return [
{
"name": "Asset Value Analytics",
"chart_name": _("Asset Value Analytics"),
"chart_type": "Report",
"report_name": "Fixed Asset Register",
"is_custom": 1,
"group_by_type": "Count",
"number_of_groups": 0,
"is_public": 0,
"timespan": "Last Year",
"time_interval": "Yearly",
"timeseries": 0,
"filters_json": json.dumps({
"company": company,
"status": "In Location",
"filter_based_on": "Fiscal Year",
"from_fiscal_year": fiscal_year.get('name'),
"to_fiscal_year": fiscal_year.get('name'),
"period_start_date": year_start_date,
"period_end_date": year_end_date,
"date_based_on": "Purchase Date",
"group_by": "--Select a group--"
}),
"type": "Bar",
"custom_options": json.dumps({
"type": "bar",
"barOptions": { "stacked": 1 },
"axisOptions": { "shortenYAxisNumbers": 1 },
"tooltipOptions": {}
}),
"doctype": "Dashboard Chart",
"y_axis": []
},
{
"name": "Category-wise Asset Value",
"chart_name": _("Category-wise Asset Value"),
"chart_type": "Report",
"report_name": "Fixed Asset Register",
"x_field": "asset_category",
"timeseries": 0,
"filters_json": json.dumps({
"company": company,
"status":"In Location",
"group_by":"Asset Category",
"is_existing_asset":0
}),
"type": "Donut",
"doctype": "Dashboard Chart",
"y_axis": [
{
"parent": "Category-wise Asset Value",
"parentfield": "y_axis",
"parenttype": "Dashboard Chart",
"y_field": "asset_value",
"doctype": "Dashboard Chart Field"
}
],
"custom_options": json.dumps({
"type": "donut",
"height": 300,
"axisOptions": {"shortenYAxisNumbers": 1}
})
},
{
"name": "Location-wise Asset Value",
"chart_name": "Location-wise Asset Value",
"chart_type": "Report",
"report_name": "Fixed Asset Register",
"x_field": "location",
"timeseries": 0,
"filters_json": json.dumps({
"company": company,
"status":"In Location",
"group_by":"Location",
"is_existing_asset":0
}),
"type": "Donut",
"doctype": "Dashboard Chart",
"y_axis": [
{
"parent": "Location-wise Asset Value",
"parentfield": "y_axis",
"parenttype": "Dashboard Chart",
"y_field": "asset_value",
"doctype": "Dashboard Chart Field"
}
],
"custom_options": json.dumps({
"type": "donut",
"height": 300,
"axisOptions": {"shortenYAxisNumbers": 1}
})
}
]
def get_number_cards(fiscal_year, year_start_date, year_end_date):
return [
{
"name": "Total Assets",
"label": _("Total Assets"),
"function": "Count",
"document_type": "Asset",
"is_public": 1,
"show_percentage_stats": 1,
"stats_time_interval": "Monthly",
"filters_json": "[]",
"doctype": "Number Card",
},
{
"name": "New Assets (This Year)",
"label": _("New Assets (This Year)"),
"function": "Count",
"document_type": "Asset",
"is_public": 1,
"show_percentage_stats": 1,
"stats_time_interval": "Monthly",
"filters_json": json.dumps([
['Asset', 'creation', 'between', [year_start_date, year_end_date]]
]),
"doctype": "Number Card",
},
{
"name": "Asset Value",
"label": _("Asset Value"),
"function": "Sum",
"aggregate_function_based_on": "value_after_depreciation",
"document_type": "Asset",
"is_public": 1,
"show_percentage_stats": 1,
"stats_time_interval": "Monthly",
"filters_json": "[]",
"doctype": "Number Card"
}
]

View File

@ -17,21 +17,27 @@
} }
], ],
"category": "Modules", "category": "Modules",
"charts": [], "charts": [
{
"chart_name": "Asset Value Analytics",
"label": "Asset Value Analytics"
}
],
"creation": "2020-03-02 15:43:27.634865", "creation": "2020-03-02 15:43:27.634865",
"developer_mode_only": 0, "developer_mode_only": 0,
"disable_user_customization": 0, "disable_user_customization": 0,
"docstatus": 0, "docstatus": 0,
"doctype": "Desk Page", "doctype": "Desk Page",
"extends_another_page": 0, "extends_another_page": 0,
"icon": "", "hide_custom": 0,
"idx": 0, "idx": 0,
"is_standard": 1, "is_standard": 1,
"label": "Assets", "label": "Assets",
"modified": "2020-04-01 11:28:51.072198", "modified": "2020-05-20 18:05:23.994795",
"modified_by": "Administrator", "modified_by": "Administrator",
"module": "Assets", "module": "Assets",
"name": "Assets", "name": "Assets",
"onboarding": "Assets",
"owner": "Administrator", "owner": "Administrator",
"pin_to_bottom": 0, "pin_to_bottom": 0,
"pin_to_top": 0, "pin_to_top": 0,
@ -42,14 +48,19 @@
"type": "DocType" "type": "DocType"
}, },
{ {
"label": "Asset Movement", "label": "Asset Category",
"link_to": "Asset Movement", "link_to": "Asset Category",
"type": "DocType" "type": "DocType"
}, },
{ {
"label": "Fixed Asset Register", "label": "Fixed Asset Register",
"link_to": "Fixed Asset Register", "link_to": "Fixed Asset Register",
"type": "Report" "type": "Report"
},
{
"label": "Assets Dashboard",
"link_to": "Asset",
"type": "Dashboard"
} }
] ]
} }

View File

@ -387,7 +387,8 @@ frappe.ui.form.on('Asset', {
} }
frm.set_value('gross_purchase_amount', item.base_net_rate + item.item_tax_amount); frm.set_value('gross_purchase_amount', item.base_net_rate + item.item_tax_amount);
frm.set_value('purchase_receipt_amount', item.base_net_rate + item.item_tax_amount); frm.set_value('purchase_receipt_amount', item.base_net_rate + item.item_tax_amount);
frm.set_value('location', item.asset_location); item.asset_location && frm.set_value('location', item.asset_location);
frm.set_value('cost_center', item.cost_center || purchase_doc.cost_center);
}, },
set_depreciation_rate: function(frm, row) { set_depreciation_rate: function(frm, row) {

View File

@ -127,6 +127,8 @@ class Asset(AccountsController):
frappe.throw(_("Available-for-use Date should be after purchase date")) frappe.throw(_("Available-for-use Date should be after purchase date"))
def validate_gross_and_purchase_amount(self): def validate_gross_and_purchase_amount(self):
if self.is_existing_asset: return
if self.gross_purchase_amount and self.gross_purchase_amount != self.purchase_receipt_amount: if self.gross_purchase_amount and self.gross_purchase_amount != self.purchase_receipt_amount:
frappe.throw(_("Gross Purchase Amount should be {} to purchase amount of one single Asset. {}\ frappe.throw(_("Gross Purchase Amount should be {} to purchase amount of one single Asset. {}\
Please do not book expense of multiple assets against one single Asset.") Please do not book expense of multiple assets against one single Asset.")

View File

@ -1,559 +1,140 @@
{ {
"allow_copy": 0, "actions": [],
"allow_guest_to_view": 0,
"allow_import": 0,
"allow_rename": 0,
"autoname": "field:asset_name", "autoname": "field:asset_name",
"beta": 0,
"creation": "2017-10-19 16:50:22.879545", "creation": "2017-10-19 16:50:22.879545",
"custom": 0,
"docstatus": 0,
"doctype": "DocType", "doctype": "DocType",
"document_type": "",
"editable_grid": 1, "editable_grid": 1,
"engine": "InnoDB", "engine": "InnoDB",
"field_order": [
"asset_name",
"asset_category",
"company",
"column_break_3",
"item_code",
"item_name",
"section_break_6",
"maintenance_team",
"column_break_9",
"maintenance_manager",
"maintenance_manager_name",
"section_break_8",
"asset_maintenance_tasks"
],
"fields": [ "fields": [
{ {
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "asset_name", "fieldname": "asset_name",
"fieldtype": "Link", "fieldtype": "Link",
"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": "Asset Name", "label": "Asset Name",
"length": 0,
"no_copy": 0,
"options": "Asset", "options": "Asset",
"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, "reqd": 1,
"search_index": 0, "unique": 1
"set_only_once": 0,
"translatable": 0,
"unique": 0
}, },
{ {
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fetch_from": "asset_name.asset_category", "fetch_from": "asset_name.asset_category",
"fieldname": "asset_category", "fieldname": "asset_category",
"fieldtype": "Read Only", "fieldtype": "Read Only",
"hidden": 0, "label": "Asset Category"
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 0,
"label": "Asset Category",
"length": 0,
"no_copy": 0,
"options": "",
"permlevel": 0,
"precision": "",
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
}, },
{ {
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fetch_from": "asset_name.item_code", "fetch_from": "asset_name.item_code",
"fieldname": "item_code", "fieldname": "item_code",
"fieldtype": "Read Only", "fieldtype": "Read Only",
"hidden": 0, "label": "Item Code"
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 0,
"label": "Item Code",
"length": 0,
"no_copy": 0,
"options": "",
"permlevel": 0,
"precision": "",
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
}, },
{ {
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fetch_from": "asset_name.item_name", "fetch_from": "asset_name.item_name",
"fieldname": "item_name", "fieldname": "item_name",
"fieldtype": "Read Only", "fieldtype": "Read Only",
"hidden": 0, "label": "Item Name"
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 0,
"label": "Item Name",
"length": 0,
"no_copy": 0,
"options": "",
"permlevel": 0,
"precision": "",
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
}, },
{ {
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "column_break_3", "fieldname": "column_break_3",
"fieldtype": "Column Break", "fieldtype": "Column Break"
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 0,
"length": 0,
"no_copy": 0,
"permlevel": 0,
"precision": "",
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
}, },
{ {
"allow_bulk_edit": 0,
"allow_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": 0,
"in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 0,
"label": "Company", "label": "Company",
"length": 0,
"no_copy": 0,
"options": "Company", "options": "Company",
"permlevel": 0, "reqd": 1
"precision": "",
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 1,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
}, },
{ {
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "select_serial_no",
"fieldtype": "Link",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 0,
"label": "Select Serial No",
"length": 0,
"no_copy": 0,
"options": "Serial No",
"permlevel": 0,
"precision": "",
"print_hide": 0,
"print_hide_if_no_value": 0,
"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_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "serial_no",
"fieldtype": "Small Text",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 0,
"label": "Serial No",
"length": 0,
"no_copy": 0,
"options": "",
"permlevel": 0,
"precision": "",
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "section_break_6", "fieldname": "section_break_6",
"fieldtype": "Section Break", "fieldtype": "Section Break"
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 0,
"length": 0,
"no_copy": 0,
"permlevel": 0,
"precision": "",
"print_hide": 0,
"print_hide_if_no_value": 0,
"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_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "maintenance_team", "fieldname": "maintenance_team",
"fieldtype": "Link", "fieldtype": "Link",
"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": "Maintenance Team", "label": "Maintenance Team",
"length": 0,
"no_copy": 0,
"options": "Asset Maintenance Team", "options": "Asset Maintenance Team",
"permlevel": 0, "reqd": 1
"precision": "",
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 1,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
}, },
{ {
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "column_break_9", "fieldname": "column_break_9",
"fieldtype": "Column Break", "fieldtype": "Column Break"
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 0,
"length": 0,
"no_copy": 0,
"permlevel": 0,
"precision": "",
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
}, },
{ {
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fetch_from": "maintenance_team.maintenance_manager", "fetch_from": "maintenance_team.maintenance_manager",
"fieldname": "maintenance_manager", "fieldname": "maintenance_manager",
"fieldtype": "Data", "fieldtype": "Data",
"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": "Maintenance Manager", "label": "Maintenance Manager",
"length": 0, "read_only": 1
"no_copy": 0,
"options": "",
"permlevel": 0,
"precision": "",
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 1,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
}, },
{ {
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fetch_from": "maintenance_team.maintenance_manager_name", "fetch_from": "maintenance_team.maintenance_manager_name",
"fieldname": "maintenance_manager_name", "fieldname": "maintenance_manager_name",
"fieldtype": "Read Only", "fieldtype": "Read Only",
"hidden": 0, "label": "Maintenance Manager Name"
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 0,
"label": "Maintenance Manager Name",
"length": 0,
"no_copy": 0,
"options": "",
"permlevel": 0,
"precision": "",
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
}, },
{ {
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "section_break_8", "fieldname": "section_break_8",
"fieldtype": "Section Break", "fieldtype": "Section Break",
"hidden": 0, "label": "Tasks"
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 0,
"label": "Tasks",
"length": 0,
"no_copy": 0,
"permlevel": 0,
"precision": "",
"print_hide": 0,
"print_hide_if_no_value": 0,
"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_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "asset_maintenance_tasks", "fieldname": "asset_maintenance_tasks",
"fieldtype": "Table", "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": "Maintenance Tasks", "label": "Maintenance Tasks",
"length": 0,
"no_copy": 0,
"options": "Asset Maintenance Task", "options": "Asset Maintenance Task",
"permlevel": 0, "reqd": 1
"precision": "",
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 1,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
} }
], ],
"has_web_view": 0, "links": [],
"hide_heading": 0, "modified": "2020-05-28 20:28:32.993823",
"hide_toolbar": 0,
"idx": 0,
"image_view": 0,
"in_create": 0,
"is_submittable": 0,
"issingle": 0,
"istable": 0,
"max_attachments": 0,
"modified": "2018-05-22 17:20:54.711885",
"modified_by": "Administrator", "modified_by": "Administrator",
"module": "Assets", "module": "Assets",
"name": "Asset Maintenance", "name": "Asset Maintenance",
"name_case": "",
"owner": "Administrator", "owner": "Administrator",
"permissions": [ "permissions": [
{ {
"amend": 0,
"cancel": 0,
"create": 1, "create": 1,
"delete": 1, "delete": 1,
"email": 1, "email": 1,
"export": 1, "export": 1,
"if_owner": 0,
"import": 0,
"permlevel": 0,
"print": 1, "print": 1,
"read": 1, "read": 1,
"report": 1, "report": 1,
"role": "Quality Manager", "role": "Quality Manager",
"set_user_permissions": 0,
"share": 1, "share": 1,
"submit": 0,
"write": 1 "write": 1
}, },
{ {
"amend": 0,
"cancel": 0,
"create": 1, "create": 1,
"delete": 1, "delete": 1,
"email": 1, "email": 1,
"export": 1, "export": 1,
"if_owner": 0,
"import": 0,
"permlevel": 0,
"print": 1, "print": 1,
"read": 1, "read": 1,
"report": 1, "report": 1,
"role": "Manufacturing User", "role": "Manufacturing User",
"set_user_permissions": 0,
"share": 1, "share": 1,
"submit": 0,
"write": 1 "write": 1
} }
], ],
"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": 1, "track_changes": 1
"track_seen": 0
} }

View File

@ -38,10 +38,10 @@ class AssetMaintenance(Document):
@frappe.whitelist() @frappe.whitelist()
def assign_tasks(asset_maintenance_name, assign_to_member, maintenance_task, next_due_date): def assign_tasks(asset_maintenance_name, assign_to_member, maintenance_task, next_due_date):
team_member = frappe.get_doc('User', assign_to_member).email team_member = frappe.db.get_value('User', assign_to_member, "email")
args = { args = {
'doctype' : 'Asset Maintenance', 'doctype' : 'Asset Maintenance',
'assign_to' : team_member, 'assign_to' : [team_member],
'name' : asset_maintenance_name, 'name' : asset_maintenance_name,
'description' : maintenance_task, 'description' : maintenance_task,
'date' : next_due_date 'date' : next_due_date
@ -77,7 +77,7 @@ def calculate_next_due_date(periodicity, start_date = None, end_date = None, las
def update_maintenance_log(asset_maintenance, item_code, item_name, task): def update_maintenance_log(asset_maintenance, item_code, item_name, task):
asset_maintenance_log = frappe.get_value("Asset Maintenance Log", {"asset_maintenance": asset_maintenance, asset_maintenance_log = frappe.get_value("Asset Maintenance Log", {"asset_maintenance": asset_maintenance,
"task": task.maintenance_task, "maintenance_status": ('in',['Planned','Overdue'])}) "task": task.name, "maintenance_status": ('in',['Planned','Overdue'])})
if not asset_maintenance_log: if not asset_maintenance_log:
asset_maintenance_log = frappe.get_doc({ asset_maintenance_log = frappe.get_doc({
@ -86,7 +86,7 @@ def update_maintenance_log(asset_maintenance, item_code, item_name, task):
"asset_name": asset_maintenance, "asset_name": asset_maintenance,
"item_code": item_code, "item_code": item_code,
"item_name": item_name, "item_name": item_name,
"task": task.maintenance_task, "task": task.name,
"has_certificate": task.certificate_required, "has_certificate": task.certificate_required,
"description": task.description, "description": task.description,
"assign_to_name": task.assign_to_name, "assign_to_name": task.assign_to_name,

View File

@ -1,789 +1,190 @@
{ {
"allow_copy": 0, "actions": [],
"allow_guest_to_view": 0,
"allow_import": 0,
"allow_rename": 0,
"autoname": "naming_series:", "autoname": "naming_series:",
"beta": 0,
"creation": "2017-10-23 16:58:44.424309", "creation": "2017-10-23 16:58:44.424309",
"custom": 0,
"docstatus": 0,
"doctype": "DocType", "doctype": "DocType",
"document_type": "Document", "document_type": "Document",
"editable_grid": 1, "editable_grid": 1,
"engine": "InnoDB", "engine": "InnoDB",
"field_order": [
"asset_maintenance",
"naming_series",
"asset_name",
"column_break_2",
"item_code",
"item_name",
"section_break_5",
"task",
"task_name",
"maintenance_type",
"periodicity",
"assign_to_name",
"column_break_6",
"due_date",
"completion_date",
"maintenance_status",
"section_break_12",
"has_certificate",
"certificate_attachement",
"section_break_6",
"description",
"column_break_9",
"actions_performed",
"amended_from"
],
"fields": [ "fields": [
{ {
"allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "asset_maintenance", "fieldname": "asset_maintenance",
"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": "Asset Maintenance", "label": "Asset Maintenance",
"length": 0, "options": "Asset Maintenance"
"no_copy": 0,
"options": "Asset Maintenance",
"permlevel": 0,
"precision": "",
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
}, },
{ {
"allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"default": "",
"fieldname": "naming_series", "fieldname": "naming_series",
"fieldtype": "Select", "fieldtype": "Select",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 0,
"label": "Series", "label": "Series",
"length": 0,
"no_copy": 0,
"options": "ACC-AML-.YYYY.-", "options": "ACC-AML-.YYYY.-",
"permlevel": 0, "reqd": 1
"precision": "",
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 1,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
}, },
{ {
"allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fetch_from": "asset_maintenance.asset_name", "fetch_from": "asset_maintenance.asset_name",
"fieldname": "asset_name", "fieldname": "asset_name",
"fieldtype": "Read Only", "fieldtype": "Read Only",
"hidden": 0, "label": "Asset Name"
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 0,
"label": "Asset Name",
"length": 0,
"no_copy": 0,
"options": "",
"permlevel": 0,
"precision": "",
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
}, },
{ {
"allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "column_break_2", "fieldname": "column_break_2",
"fieldtype": "Column Break", "fieldtype": "Column Break"
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 0,
"length": 0,
"no_copy": 0,
"permlevel": 0,
"precision": "",
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
}, },
{ {
"allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fetch_from": "asset_maintenance.item_code", "fetch_from": "asset_maintenance.item_code",
"fieldname": "item_code", "fieldname": "item_code",
"fieldtype": "Read Only", "fieldtype": "Read Only",
"hidden": 0, "label": "Item Code"
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 0,
"label": "Item Code",
"length": 0,
"no_copy": 0,
"options": "",
"permlevel": 0,
"precision": "",
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
}, },
{ {
"allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fetch_from": "asset_maintenance.item_name", "fetch_from": "asset_maintenance.item_name",
"fieldname": "item_name", "fieldname": "item_name",
"fieldtype": "Read Only", "fieldtype": "Read Only",
"hidden": 0, "label": "Item Name"
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 0,
"label": "Item Name",
"length": 0,
"no_copy": 0,
"options": "",
"permlevel": 0,
"precision": "",
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
}, },
{ {
"allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "section_break_5", "fieldname": "section_break_5",
"fieldtype": "Section Break", "fieldtype": "Section Break"
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 0,
"length": 0,
"no_copy": 0,
"permlevel": 0,
"precision": "",
"print_hide": 0,
"print_hide_if_no_value": 0,
"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": "task", "fieldname": "task",
"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": "Task", "label": "Task",
"length": 0, "options": "Asset Maintenance Task"
"no_copy": 0,
"options": "Asset Maintenance Task",
"permlevel": 0,
"precision": "",
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
}, },
{ {
"allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fetch_from": "task.maintenance_type", "fetch_from": "task.maintenance_type",
"fieldname": "maintenance_type", "fieldname": "maintenance_type",
"fieldtype": "Read Only", "fieldtype": "Read Only",
"hidden": 0, "label": "Maintenance Type"
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 0,
"label": "Maintenance Type",
"length": 0,
"no_copy": 0,
"options": "",
"permlevel": 0,
"precision": "",
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
}, },
{ {
"allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fetch_from": "task.periodicity", "fetch_from": "task.periodicity",
"fieldname": "periodicity", "fieldname": "periodicity",
"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": "Periodicity", "label": "Periodicity",
"length": 0, "read_only": 1
"no_copy": 0,
"options": "",
"permlevel": 0,
"precision": "",
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 1,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
}, },
{ {
"allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fetch_from": "task.assign_to_name", "fetch_from": "task.assign_to_name",
"fieldname": "assign_to_name", "fieldname": "assign_to_name",
"fieldtype": "Read Only", "fieldtype": "Read Only",
"hidden": 0, "label": "Assign To"
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 0,
"label": "Assign To",
"length": 0,
"no_copy": 0,
"options": "",
"permlevel": 0,
"precision": "",
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
}, },
{ {
"allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "column_break_6", "fieldname": "column_break_6",
"fieldtype": "Column Break", "fieldtype": "Column Break"
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 0,
"length": 0,
"no_copy": 0,
"permlevel": 0,
"precision": "",
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
}, },
{ {
"allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fetch_from": "task.next_due_date", "fetch_from": "task.next_due_date",
"fieldname": "due_date", "fieldname": "due_date",
"fieldtype": "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_list_view": 1,
"in_standard_filter": 0,
"label": "Due Date", "label": "Due Date",
"length": 0, "read_only": 1
"no_copy": 0,
"options": "",
"permlevel": 0,
"precision": "",
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 1,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
}, },
{ {
"allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "completion_date", "fieldname": "completion_date",
"fieldtype": "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_list_view": 1,
"in_standard_filter": 0, "label": "Completion Date"
"label": "Completion Date",
"length": 0,
"no_copy": 0,
"permlevel": 0,
"precision": "",
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
}, },
{ {
"allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "maintenance_status", "fieldname": "maintenance_status",
"fieldtype": "Select", "fieldtype": "Select",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 1, "in_standard_filter": 1,
"label": "Maintenance Status", "label": "Maintenance Status",
"length": 0,
"no_copy": 0,
"options": "Planned\nCompleted\nCancelled\nOverdue", "options": "Planned\nCompleted\nCancelled\nOverdue",
"permlevel": 0, "reqd": 1
"precision": "",
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 1,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
}, },
{ {
"allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "section_break_12", "fieldname": "section_break_12",
"fieldtype": "Section Break", "fieldtype": "Section Break"
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 0,
"length": 0,
"no_copy": 0,
"permlevel": 0,
"precision": "",
"print_hide": 0,
"print_hide_if_no_value": 0,
"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, "default": "0",
"allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fetch_from": "task.certificate_required", "fetch_from": "task.certificate_required",
"fieldname": "has_certificate", "fieldname": "has_certificate",
"fieldtype": "Check", "fieldtype": "Check",
"hidden": 0, "label": "Has Certificate "
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 0,
"label": "Has Certificate ",
"length": 0,
"no_copy": 0,
"options": "",
"permlevel": 0,
"precision": "",
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
}, },
{ {
"allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"depends_on": "eval:doc.has_certificate", "depends_on": "eval:doc.has_certificate",
"fieldname": "certificate_attachement", "fieldname": "certificate_attachement",
"fieldtype": "Attach", "fieldtype": "Attach",
"hidden": 0, "label": "Certificate"
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 0,
"label": "Certificate",
"length": 0,
"no_copy": 0,
"permlevel": 0,
"precision": "",
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
}, },
{ {
"allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "section_break_6", "fieldname": "section_break_6",
"fieldtype": "Column Break", "fieldtype": "Column Break"
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 0,
"length": 0,
"no_copy": 0,
"permlevel": 0,
"precision": "",
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
}, },
{ {
"allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fetch_from": "task.description", "fetch_from": "task.description",
"fieldname": "description", "fieldname": "description",
"fieldtype": "Read Only", "fieldtype": "Read Only",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 0,
"label": "Description", "label": "Description",
"length": 0, "read_only": 1
"no_copy": 0,
"options": "",
"permlevel": 0,
"precision": "",
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 1,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
}, },
{ {
"allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "column_break_9", "fieldname": "column_break_9",
"fieldtype": "Section Break", "fieldtype": "Section Break"
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 0,
"length": 0,
"no_copy": 0,
"permlevel": 0,
"precision": "",
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
}, },
{ {
"allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 1, "allow_on_submit": 1,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "actions_performed", "fieldname": "actions_performed",
"fieldtype": "Text Editor", "fieldtype": "Text Editor",
"hidden": 0, "label": "Actions performed"
"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 performed",
"length": 0,
"no_copy": 0,
"permlevel": 0,
"precision": "",
"print_hide": 0,
"print_hide_if_no_value": 0,
"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": "amended_from", "fieldname": "amended_from",
"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": "Amended From", "label": "Amended From",
"length": 0,
"no_copy": 1, "no_copy": 1,
"options": "Asset Maintenance Log", "options": "Asset Maintenance Log",
"permlevel": 0,
"precision": "",
"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": 0, "fetch_from": "task.maintenance_task",
"reqd": 0, "fieldname": "task_name",
"search_index": 0, "fieldtype": "Data",
"set_only_once": 0, "in_preview": 1,
"translatable": 0, "label": "Task Name",
"unique": 0 "read_only": 1
} }
], ],
"has_web_view": 0,
"hide_heading": 0,
"hide_toolbar": 0,
"idx": 0,
"image_view": 0,
"in_create": 0,
"is_submittable": 1, "is_submittable": 1,
"issingle": 0, "links": [],
"istable": 0, "modified": "2020-05-28 20:51:48.238397",
"max_attachments": 0,
"modified": "2018-08-21 14:44:51.457835",
"modified_by": "Administrator", "modified_by": "Administrator",
"module": "Assets", "module": "Assets",
"name": "Asset Maintenance Log", "name": "Asset Maintenance Log",
"name_case": "",
"owner": "Administrator", "owner": "Administrator",
"permissions": [ "permissions": [
{ {
@ -793,27 +194,17 @@
"delete": 1, "delete": 1,
"email": 1, "email": 1,
"export": 1, "export": 1,
"if_owner": 0,
"import": 0,
"permlevel": 0,
"print": 1, "print": 1,
"read": 1, "read": 1,
"report": 1, "report": 1,
"role": "Manufacturing User", "role": "Manufacturing User",
"set_user_permissions": 0,
"share": 1, "share": 1,
"submit": 1, "submit": 1,
"write": 1 "write": 1
} }
], ],
"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",
"title_field": "",
"track_changes": 1, "track_changes": 1,
"track_seen": 1, "track_seen": 1
"track_views": 0
} }

View File

@ -7,5 +7,4 @@ import frappe
from frappe.model.document import Document from frappe.model.document import Document
class AssetMaintenanceTask(Document): class AssetMaintenanceTask(Document):
def autoname(self): pass
self.name = self.maintenance_task

View File

@ -0,0 +1,42 @@
{
"allow_roles": [
{
"role": "Accounts User"
},
{
"role": "Maintenance User"
}
],
"creation": "2020-05-08 15:10:45.571457",
"docstatus": 0,
"doctype": "Module Onboarding",
"documentation_url": "https://docs.erpnext.com/docs/user/manual/en/asset",
"idx": 0,
"is_complete": 0,
"modified": "2020-05-08 16:17:31.685943",
"modified_by": "Administrator",
"module": "Assets",
"name": "Assets",
"owner": "Administrator",
"steps": [
{
"step": "Introduction to Assets"
},
{
"step": "Create a Fixed Asset Item"
},
{
"step": "Create an Asset Category"
},
{
"step": "Purchase an Asset Item"
},
{
"step": "Create an Asset"
}
],
"subtitle": "Assets, Depreciations, Repairs and more",
"success_message": "The Asset Module is all set up!",
"title": "Let's Setup Asset Management",
"user_can_dismiss": 1
}

View File

@ -0,0 +1,16 @@
{
"action": "Create Entry",
"creation": "2020-05-08 13:20:00.259985",
"docstatus": 0,
"doctype": "Onboarding Step",
"idx": 0,
"is_complete": 0,
"is_mandatory": 0,
"is_skipped": 0,
"modified": "2020-05-08 13:20:00.259985",
"modified_by": "Administrator",
"name": "Create a Fixed Asset Item",
"owner": "Administrator",
"reference_document": "Item",
"title": "Create a Fixed Asset Item"
}

View File

@ -0,0 +1,16 @@
{
"action": "Create Entry",
"creation": "2020-05-08 13:21:53.332538",
"docstatus": 0,
"doctype": "Onboarding Step",
"idx": 0,
"is_complete": 0,
"is_mandatory": 0,
"is_skipped": 0,
"modified": "2020-05-08 13:21:53.332538",
"modified_by": "Administrator",
"name": "Create an Asset",
"owner": "Administrator",
"reference_document": "Asset",
"title": "Create an Asset"
}

View File

@ -0,0 +1,16 @@
{
"action": "Create Entry",
"creation": "2020-05-08 13:21:53.332538",
"docstatus": 0,
"doctype": "Onboarding Step",
"idx": 0,
"is_complete": 0,
"is_mandatory": 0,
"is_skipped": 0,
"modified": "2020-05-08 13:21:53.332538",
"modified_by": "Administrator",
"name": "Create an Asset Category",
"owner": "Administrator",
"reference_document": "Asset Category",
"title": "Create an Asset Category"
}

View File

@ -0,0 +1,16 @@
{
"action": "Watch Video",
"creation": "2020-05-08 13:18:25.424715",
"docstatus": 0,
"doctype": "Onboarding Step",
"idx": 0,
"is_complete": 0,
"is_mandatory": 0,
"is_skipped": 0,
"modified": "2020-05-08 16:06:16.625646",
"modified_by": "Administrator",
"name": "Introduction to Assets",
"owner": "Administrator",
"title": "Introduction to Assets",
"video_url": "https://www.youtube.com/watch?v=I-K8pLRmvSo"
}

View File

@ -0,0 +1,16 @@
{
"action": "Create Entry",
"creation": "2020-05-08 13:21:28.208059",
"docstatus": 0,
"doctype": "Onboarding Step",
"idx": 0,
"is_complete": 0,
"is_mandatory": 0,
"is_skipped": 0,
"modified": "2020-05-08 13:21:28.208059",
"modified_by": "Administrator",
"name": "Purchase an Asset Item",
"owner": "Administrator",
"reference_document": "Purchase Receipt",
"title": "Purchase an Asset Item"
}

View File

@ -21,20 +21,54 @@ frappe.query_reports["Fixed Asset Register"] = {
reqd: 1 reqd: 1
}, },
{ {
fieldname:"purchase_date", "fieldname":"filter_based_on",
label: __("Purchase Date"), "label": __("Period Based On"),
fieldtype: "Date" "fieldtype": "Select",
"options": ["Fiscal Year", "Date Range"],
"default": ["Fiscal Year"],
"reqd": 1
}, },
{ {
fieldname:"available_for_use_date", "fieldname":"from_date",
label: __("Available For Use Date"), "label": __("Start Date"),
fieldtype: "Date" "fieldtype": "Date",
"default": frappe.datetime.add_months(frappe.datetime.nowdate(), -12),
"depends_on": "eval: doc.filter_based_on == 'Date Range'",
"reqd": 1
}, },
{ {
fieldname:"finance_book", "fieldname":"to_date",
label: __("Finance Book"), "label": __("End Date"),
fieldtype: "Link", "fieldtype": "Date",
options: "Finance Book" "default": frappe.datetime.nowdate(),
"depends_on": "eval: doc.filter_based_on == 'Date Range'",
"reqd": 1
},
{
"fieldname":"from_fiscal_year",
"label": __("Start Year"),
"fieldtype": "Link",
"options": "Fiscal Year",
"default": frappe.defaults.get_user_default("fiscal_year"),
"depends_on": "eval: doc.filter_based_on == 'Fiscal Year'",
"reqd": 1
},
{
"fieldname":"to_fiscal_year",
"label": __("End Year"),
"fieldtype": "Link",
"options": "Fiscal Year",
"default": frappe.defaults.get_user_default("fiscal_year"),
"depends_on": "eval: doc.filter_based_on == 'Fiscal Year'",
"reqd": 1
},
{
"fieldname":"date_based_on",
"label": __("Date Based On"),
"fieldtype": "Select",
"options": ["Purchase Date", "Available For Use Date"],
"default": "Purchase Date",
"reqd": 1
}, },
{ {
fieldname:"asset_category", fieldname:"asset_category",
@ -42,6 +76,26 @@ frappe.query_reports["Fixed Asset Register"] = {
fieldtype: "Link", fieldtype: "Link",
options: "Asset Category" options: "Asset Category"
}, },
{
fieldname:"finance_book",
label: __("Finance Book"),
fieldtype: "Link",
options: "Finance Book"
},
{
fieldname:"cost_center",
label: __("Cost Center"),
fieldtype: "Link",
options: "Cost Center"
},
{
fieldname:"group_by",
label: __("Group By"),
fieldtype: "Select",
options: ["--Select a group--", "Asset Category", "Location"],
default: "--Select a group--",
reqd: 1
},
{ {
fieldname:"is_existing_asset", fieldname:"is_existing_asset",
label: __("Is Existing Asset"), label: __("Is Existing Asset"),

View File

@ -4,122 +4,39 @@
from __future__ import unicode_literals from __future__ import unicode_literals
import frappe import frappe
from frappe import _ from frappe import _
from frappe.utils import cstr, today, flt from frappe.utils import cstr, today, flt, add_years, formatdate, getdate
from erpnext.accounts.report.financial_statements import get_period_list, get_fiscal_year_data, validate_fiscal_year
def execute(filters=None): def execute(filters=None):
filters = frappe._dict(filters or {}) filters = frappe._dict(filters or {})
columns = get_columns(filters) columns = get_columns(filters)
data = get_data(filters) data = get_data(filters)
return columns, data chart = prepare_chart_data(data, filters) if filters.get("group_by") not in ("Asset Category", "Location") else {}
def get_columns(filters): return columns, data, None, chart
return [
{
"label": _("Asset Id"),
"fieldtype": "Link",
"fieldname": "asset_id",
"options": "Asset",
"width": 100
},
{
"label": _("Asset Name"),
"fieldtype": "Data",
"fieldname": "asset_name",
"width": 140
},
{
"label": _("Asset Category"),
"fieldtype": "Link",
"fieldname": "asset_category",
"options": "Asset Category",
"width": 100
},
{
"label": _("Status"),
"fieldtype": "Data",
"fieldname": "status",
"width": 90
},
{
"label": _("Purchase Date"),
"fieldtype": "Date",
"fieldname": "purchase_date",
"width": 90
},
{
"label": _("Available For Use Date"),
"fieldtype": "Date",
"fieldname": "available_for_use_date",
"width": 90
},
{
"label": _("Gross Purchase Amount"),
"fieldname": "gross_purchase_amount",
"options": "Currency",
"width": 90
},
{
"label": _("Asset Value"),
"fieldname": "asset_value",
"options": "Currency",
"width": 90
},
{
"label": _("Opening Accumulated Depreciation"),
"fieldname": "opening_accumulated_depreciation",
"options": "Currency",
"width": 90
},
{
"label": _("Depreciated Amount"),
"fieldname": "depreciated_amount",
"options": "Currency",
"width": 90
},
{
"label": _("Cost Center"),
"fieldtype": "Link",
"fieldname": "cost_center",
"options": "Cost Center",
"width": 100
},
{
"label": _("Department"),
"fieldtype": "Link",
"fieldname": "department",
"options": "Department",
"width": 100
},
{
"label": _("Vendor Name"),
"fieldtype": "Data",
"fieldname": "vendor_name",
"width": 100
},
{
"label": _("Location"),
"fieldtype": "Link",
"fieldname": "location",
"options": "Location",
"width": 100
},
]
def get_conditions(filters): def get_conditions(filters):
conditions = { 'docstatus': 1 } conditions = { 'docstatus': 1 }
status = filters.status status = filters.status
date = filters.date date_field = frappe.scrub(filters.date_based_on or "Purchase Date")
if filters.get('company'): if filters.get('company'):
conditions["company"] = filters.company conditions["company"] = filters.company
if filters.get('purchase_date'): if filters.filter_based_on == "Date Range":
conditions["purchase_date"] = ('<=', filters.get('purchase_date')) conditions[date_field] = ["between", [filters.from_date, filters.to_date]]
if filters.get('available_for_use_date'): if filters.filter_based_on == "Fiscal Year":
conditions["available_for_use_date"] = ('<=', filters.get('available_for_use_date')) fiscal_year = get_fiscal_year_data(filters.from_fiscal_year, filters.to_fiscal_year)
validate_fiscal_year(fiscal_year, filters.from_fiscal_year, filters.to_fiscal_year)
filters.year_start_date = getdate(fiscal_year.year_start_date)
filters.year_end_date = getdate(fiscal_year.year_end_date)
conditions[date_field] = ["between", [filters.year_start_date, filters.year_end_date]]
if filters.get('is_existing_asset'): if filters.get('is_existing_asset'):
conditions["is_existing_asset"] = filters.get('is_existing_asset') conditions["is_existing_asset"] = filters.get('is_existing_asset')
if filters.get('asset_category'): if filters.get('asset_category'):
conditions["asset_category"] = filters.get('asset_category') conditions["asset_category"] = filters.get('asset_category')
if filters.get('cost_center'):
conditions["cost_center"] = filters.get('cost_center')
# In Store assets are those that are not sold or scrapped # In Store assets are those that are not sold or scrapped
operand = 'not in' operand = 'not in'
@ -139,18 +56,28 @@ def get_data(filters):
pr_supplier_map = get_purchase_receipt_supplier_map() pr_supplier_map = get_purchase_receipt_supplier_map()
pi_supplier_map = get_purchase_invoice_supplier_map() pi_supplier_map = get_purchase_invoice_supplier_map()
assets_record = frappe.db.get_all("Asset", group_by = frappe.scrub(filters.get("group_by"))
filters=conditions,
fields=["name", "asset_name", "department", "cost_center", "purchase_receipt", if group_by == "asset_category":
fields = ["asset_category", "gross_purchase_amount", "opening_accumulated_depreciation"]
assets_record = frappe.db.get_all("Asset", filters=conditions, fields=fields, group_by=group_by)
elif group_by == "location":
fields = ["location", "gross_purchase_amount", "opening_accumulated_depreciation"]
assets_record = frappe.db.get_all("Asset", filters=conditions, fields=fields, group_by=group_by)
else:
fields = ["name as asset_id", "asset_name", "status", "department", "cost_center", "purchase_receipt",
"asset_category", "purchase_date", "gross_purchase_amount", "location", "asset_category", "purchase_date", "gross_purchase_amount", "location",
"available_for_use_date", "status", "purchase_invoice", "opening_accumulated_depreciation"]) "available_for_use_date", "purchase_invoice", "opening_accumulated_depreciation"]
assets_record = frappe.db.get_all("Asset", filters=conditions, fields=fields)
for asset in assets_record: for asset in assets_record:
asset_value = asset.gross_purchase_amount - flt(asset.opening_accumulated_depreciation) \ asset_value = asset.gross_purchase_amount - flt(asset.opening_accumulated_depreciation) \
- flt(depreciation_amount_map.get(asset.name)) - flt(depreciation_amount_map.get(asset.name))
if asset_value: if asset_value:
row = { row = {
"asset_id": asset.name, "asset_id": asset.asset_id,
"asset_name": asset.asset_name, "asset_name": asset.asset_name,
"status": asset.status, "status": asset.status,
"department": asset.department, "department": asset.department,
@ -158,7 +85,7 @@ def get_data(filters):
"vendor_name": pr_supplier_map.get(asset.purchase_receipt) or pi_supplier_map.get(asset.purchase_invoice), "vendor_name": pr_supplier_map.get(asset.purchase_receipt) or pi_supplier_map.get(asset.purchase_invoice),
"gross_purchase_amount": asset.gross_purchase_amount, "gross_purchase_amount": asset.gross_purchase_amount,
"opening_accumulated_depreciation": asset.opening_accumulated_depreciation, "opening_accumulated_depreciation": asset.opening_accumulated_depreciation,
"depreciated_amount": depreciation_amount_map.get(asset.name) or 0.0, "depreciated_amount": depreciation_amount_map.get(asset.asset_id) or 0.0,
"available_for_use_date": asset.available_for_use_date, "available_for_use_date": asset.available_for_use_date,
"location": asset.location, "location": asset.location,
"asset_category": asset.asset_category, "asset_category": asset.asset_category,
@ -169,8 +96,39 @@ def get_data(filters):
return data return data
def prepare_chart_data(data, filters):
labels_values_map = {}
date_field = frappe.scrub(filters.date_based_on)
period_list = get_period_list(filters.from_fiscal_year, filters.to_fiscal_year,
filters.from_date, filters.to_date, filters.filter_based_on, "Monthly", company=filters.company)
for d in period_list:
labels_values_map.setdefault(d.get('label'), frappe._dict({'asset_value': 0, 'depreciated_amount': 0}))
for d in data:
date = d.get(date_field)
belongs_to_month = formatdate(date, "MMM YYYY")
labels_values_map[belongs_to_month].asset_value += d.get("asset_value")
labels_values_map[belongs_to_month].depreciated_amount += d.get("depreciated_amount")
return {
"data" : {
"labels": labels_values_map.keys(),
"datasets": [
{ 'name': _('Asset Value'), 'values': [d.get("asset_value") for d in labels_values_map.values()] },
{ 'name': _('Depreciatied Amount'), 'values': [d.get("depreciated_amount") for d in labels_values_map.values()] }
]
},
"type": "bar",
"barOptions": {
"stacked": 1
},
}
def get_finance_book_value_map(filters): def get_finance_book_value_map(filters):
date = filters.get('purchase_date') or filters.get('available_for_use_date') or today() date = filters.to_date if filters.filter_based_on == "Date Range" else filters.year_end_date
return frappe._dict(frappe.db.sql(''' Select return frappe._dict(frappe.db.sql(''' Select
parent, SUM(depreciation_amount) parent, SUM(depreciation_amount)
@ -201,3 +159,139 @@ def get_purchase_invoice_supplier_map():
AND pii.is_fixed_asset=1 AND pii.is_fixed_asset=1
AND pi.docstatus=1 AND pi.docstatus=1
AND pi.is_return=0''')) AND pi.is_return=0'''))
def get_columns(filters):
if filters.get("group_by") in ["Asset Category", "Location"]:
return [
{
"label": _("{}").format(filters.get("group_by")),
"fieldtype": "Link",
"fieldname": frappe.scrub(filters.get("group_by")),
"options": filters.get("group_by"),
"width": 120
},
{
"label": _("Gross Purchase Amount"),
"fieldname": "gross_purchase_amount",
"fieldtype": "Currency",
"options": "company:currency",
"width": 100
},
{
"label": _("Opening Accumulated Depreciation"),
"fieldname": "opening_accumulated_depreciation",
"fieldtype": "Currency",
"options": "company:currency",
"width": 90
},
{
"label": _("Depreciated Amount"),
"fieldname": "depreciated_amount",
"fieldtype": "Currency",
"options": "company:currency",
"width": 100
},
{
"label": _("Asset Value"),
"fieldname": "asset_value",
"fieldtype": "Currency",
"options": "company:currency",
"width": 100
}
]
return [
{
"label": _("Asset Id"),
"fieldtype": "Link",
"fieldname": "asset_id",
"options": "Asset",
"width": 60
},
{
"label": _("Asset Name"),
"fieldtype": "Data",
"fieldname": "asset_name",
"width": 140
},
{
"label": _("Asset Category"),
"fieldtype": "Link",
"fieldname": "asset_category",
"options": "Asset Category",
"width": 100
},
{
"label": _("Status"),
"fieldtype": "Data",
"fieldname": "status",
"width": 80
},
{
"label": _("Purchase Date"),
"fieldtype": "Date",
"fieldname": "purchase_date",
"width": 90
},
{
"label": _("Available For Use Date"),
"fieldtype": "Date",
"fieldname": "available_for_use_date",
"width": 90
},
{
"label": _("Gross Purchase Amount"),
"fieldname": "gross_purchase_amount",
"fieldtype": "Currency",
"options": "company:currency",
"width": 100
},
{
"label": _("Asset Value"),
"fieldname": "asset_value",
"fieldtype": "Currency",
"options": "company:currency",
"width": 100
},
{
"label": _("Opening Accumulated Depreciation"),
"fieldname": "opening_accumulated_depreciation",
"fieldtype": "Currency",
"options": "company:currency",
"width": 90
},
{
"label": _("Depreciated Amount"),
"fieldname": "depreciated_amount",
"fieldtype": "Currency",
"options": "company:currency",
"width": 100
},
{
"label": _("Cost Center"),
"fieldtype": "Link",
"fieldname": "cost_center",
"options": "Cost Center",
"width": 100
},
{
"label": _("Department"),
"fieldtype": "Link",
"fieldname": "department",
"options": "Department",
"width": 100
},
{
"label": _("Vendor Name"),
"fieldtype": "Data",
"fieldname": "vendor_name",
"width": 100
},
{
"label": _("Location"),
"fieldtype": "Link",
"fieldname": "location",
"options": "Location",
"width": 100
},
]

View File

@ -0,0 +1,211 @@
# Copyright (c) 2020, Frappe Technologies Pvt. Ltd. and Contributors
# License: GNU General Public License v3. See license.txt
import frappe
import json
from frappe import _
from frappe.utils import nowdate
from erpnext.accounts.dashboard_fixtures import _get_fiscal_year
def get_data():
fiscal_year = _get_fiscal_year(nowdate())
if not fiscal_year:
return frappe._dict()
company = frappe.get_doc("Company", get_company_for_dashboards())
fiscal_year_name = fiscal_year.get("name")
start_date = str(fiscal_year.get("year_start_date"))
end_date = str(fiscal_year.get("year_end_date"))
return frappe._dict({
"dashboards": get_dashboards(),
"charts": get_charts(company, fiscal_year_name, start_date, end_date),
"number_cards": get_number_cards(company, fiscal_year_name, start_date, end_date),
})
def get_company_for_dashboards():
company = frappe.defaults.get_defaults().company
if company:
return company
else:
company_list = frappe.get_list("Company")
if company_list:
return company_list[0].name
return None
def get_dashboards():
return [{
"name": "Buying",
"dashboard_name": "Buying",
"charts": [
{ "chart": "Purchase Order Trends", "width": "Full"},
{ "chart": "Material Request Analysis", "width": "Half"},
{ "chart": "Purchase Order Analysis", "width": "Half"},
{ "chart": "Top Suppliers", "width": "Full"}
],
"cards": [
{ "card": "Annual Purchase"},
{ "card": "Purchase Orders to Receive"},
{ "card": "Purchase Orders to Bill"},
{ "card": "Active Suppliers"}
]
}]
def get_charts(company, fiscal_year_name, start_date, end_date):
return [
{
"name": "Purchase Order Analysis",
"chart_name": _("Purchase Order Analysis"),
"chart_type": "Report",
"custom_options": json.dumps({
"type": "donut",
"height": 300,
"axisOptions": {"shortenYAxisNumbers": 1}
}),
"doctype": "Dashboard Chart",
"filters_json": json.dumps({
"company": company.name,
"from_date": start_date,
"to_date": end_date
}),
"is_custom": 1,
"is_public": 1,
"owner": "Administrator",
"report_name": "Purchase Order Analysis",
"type": "Donut"
},
{
"name": "Material Request Analysis",
"chart_name": _("Material Request Analysis"),
"chart_type": "Group By",
"custom_options": json.dumps({"height": 300}),
"doctype": "Dashboard Chart",
"document_type": "Material Request",
"filters_json": json.dumps(
[["Material Request", "status", "not in", ["Draft", "Cancelled", "Stopped", None], False],
["Material Request", "material_request_type", "=", "Purchase", False],
["Material Request", "company", "=", company.name, False],
["Material Request", "docstatus", "=", 1, False],
["Material Request", "transaction_date", "Between", [start_date, end_date], False]]
),
"group_by_based_on": "status",
"group_by_type": "Count",
"is_custom": 0,
"is_public": 1,
"number_of_groups": 0,
"owner": "Administrator",
"type": "Donut"
},
{
"name": "Purchase Order Trends",
"chart_name": _("Purchase Order Trends"),
"chart_type": "Report",
"custom_options": json.dumps({
"type": "line",
"axisOptions": {"shortenYAxisNumbers": 1},
"tooltipOptions": {},
"lineOptions": {
"regionFill": 1
}
}),
"doctype": "Dashboard Chart",
"filters_json": json.dumps({
"company": company.name,
"period": "Monthly",
"fiscal_year": fiscal_year_name,
"period_based_on": "posting_date",
"based_on": "Item"
}),
"is_custom": 1,
"is_public": 1,
"owner": "Administrator",
"report_name": "Purchase Order Trends",
"type": "Line"
},
{
"name": "Top Suppliers",
"chart_name": _("Top Suppliers"),
"chart_type": "Report",
"doctype": "Dashboard Chart",
"filters_json": json.dumps({
"company": company.name,
"period": "Monthly",
"fiscal_year": fiscal_year_name,
"period_based_on": "posting_date",
"based_on": "Supplier"
}),
"is_custom": 1,
"is_public": 1,
"owner": "Administrator",
"report_name": "Purchase Receipt Trends",
"type": "Bar"
}
]
def get_number_cards(company, fiscal_year_name, start_date, end_date):
return [
{
"name": "Annual Purchase",
"aggregate_function_based_on": "base_net_total",
"doctype": "Number Card",
"document_type": "Purchase Order",
"filters_json": json.dumps([
["Purchase Order", "transaction_date", "Between", [start_date, end_date], False],
["Purchase Order", "status", "not in", ["Draft", "Cancelled", "Closed", None], False],
["Purchase Order", "docstatus", "=", 1, False],
["Purchase Order", "company", "=", company.name, False]
]),
"function": "Sum",
"is_public": 1,
"label": _("Annual Purchase"),
"owner": "Administrator",
"show_percentage_stats": 1,
"stats_time_interval": "Monthly"
},
{
"name": "Purchase Orders to Receive",
"doctype": "Number Card",
"document_type": "Purchase Order",
"filters_json": json.dumps([
["Purchase Order", "status", "in", ["To Receive and Bill", "To Receive", None], False],
["Purchase Order", "docstatus", "=", 1, False],
["Purchase Order", "company", "=", company.name, False]
]),
"function": "Count",
"is_public": 1,
"label": _("Purchase Orders to Receive"),
"owner": "Administrator",
"show_percentage_stats": 1,
"stats_time_interval": "Weekly"
},
{
"name": "Purchase Orders to Bill",
"doctype": "Number Card",
"document_type": "Purchase Order",
"filters_json": json.dumps([
["Purchase Order", "status", "in", ["To Receive and Bill", "To Bill", None], False],
["Purchase Order", "docstatus", "=", 1, False],
["Purchase Order", "company", "=", company.name, False]
]),
"function": "Count",
"is_public": 1,
"label": _("Purchase Orders to Bill"),
"owner": "Administrator",
"show_percentage_stats": 1,
"stats_time_interval": "Weekly"
},
{
"name": "Active Suppliers",
"doctype": "Number Card",
"document_type": "Supplier",
"filters_json": json.dumps([["Supplier", "disabled", "=", "0"]]),
"function": "Count",
"is_public": 1,
"label": "Active Suppliers",
"owner": "Administrator",
"show_percentage_stats": 1,
"stats_time_interval": "Monthly"
}
]

View File

@ -2,24 +2,24 @@
"cards": [ "cards": [
{ {
"hidden": 0, "hidden": 0,
"label": "Supplier", "label": "Buying",
"links": "[\n {\n \"description\": \"Supplier database.\",\n \"label\": \"Supplier\",\n \"name\": \"Supplier\",\n \"onboard\": 1,\n \"type\": \"doctype\"\n },\n {\n \"description\": \"Supplier Group master.\",\n \"label\": \"Supplier Group\",\n \"name\": \"Supplier Group\",\n \"type\": \"doctype\"\n },\n {\n \"description\": \"All Contacts.\",\n \"label\": \"Contact\",\n \"name\": \"Contact\",\n \"type\": \"doctype\"\n },\n {\n \"description\": \"All Addresses.\",\n \"label\": \"Address\",\n \"name\": \"Address\",\n \"type\": \"doctype\"\n }\n]" "links": "[ \n {\n \"dependencies\": [\n \"Item\"\n ],\n \"description\": \"Request for purchase.\",\n \"label\": \"Material Request\",\n \"name\": \"Material Request\",\n \"onboard\": 1,\n \"type\": \"doctype\"\n },\n {\n \"dependencies\": [\n \"Item\",\n \"Supplier\"\n ],\n \"description\": \"Purchase Orders given to Suppliers.\",\n \"label\": \"Purchase Order\",\n \"name\": \"Purchase Order\",\n \"onboard\": 1,\n \"type\": \"doctype\"\n },\n {\n \"dependencies\": [\n \"Item\",\n \"Supplier\"\n ],\n \"label\": \"Purchase Invoice\",\n \"name\": \"Purchase Invoice\",\n \"onboard\": 1,\n \"type\": \"doctype\"\n },\n {\n \"dependencies\": [\n \"Item\",\n \"Supplier\"\n ],\n \"description\": \"Request for quotation.\",\n \"label\": \"Request for Quotation\",\n \"name\": \"Request for Quotation\",\n \"onboard\": 1,\n \"type\": \"doctype\"\n },\n {\n \"dependencies\": [\n \"Item\",\n \"Supplier\"\n ],\n \"description\": \"Quotations received from Suppliers.\",\n \"label\": \"Supplier Quotation\",\n \"name\": \"Supplier Quotation\",\n \"type\": \"doctype\"\n }\n]"
}, },
{ {
"hidden": 0, "hidden": 0,
"label": "Purchasing", "label": "Items & Pricing",
"links": "[\n {\n \"dependencies\": [\n \"Item\",\n \"Supplier\"\n ],\n \"description\": \"Purchase Orders given to Suppliers.\",\n \"label\": \"Purchase Order\",\n \"name\": \"Purchase Order\",\n \"onboard\": 1,\n \"type\": \"doctype\"\n },\n {\n \"dependencies\": [\n \"Item\",\n \"Supplier\"\n ],\n \"label\": \"Purchase Invoice\",\n \"name\": \"Purchase Invoice\",\n \"onboard\": 1,\n \"type\": \"doctype\"\n },\n {\n \"dependencies\": [\n \"Item\"\n ],\n \"description\": \"Request for purchase.\",\n \"label\": \"Material Request\",\n \"name\": \"Material Request\",\n \"onboard\": 1,\n \"type\": \"doctype\"\n },\n {\n \"dependencies\": [\n \"Item\",\n \"Supplier\"\n ],\n \"description\": \"Request for quotation.\",\n \"label\": \"Request for Quotation\",\n \"name\": \"Request for Quotation\",\n \"onboard\": 1,\n \"type\": \"doctype\"\n },\n {\n \"dependencies\": [\n \"Item\",\n \"Supplier\"\n ],\n \"description\": \"Quotations received from Suppliers.\",\n \"label\": \"Supplier Quotation\",\n \"name\": \"Supplier Quotation\",\n \"type\": \"doctype\"\n }\n]" "links": "[\n {\n \"description\": \"All Products or Services.\",\n \"label\": \"Item\",\n \"name\": \"Item\",\n \"onboard\": 1,\n \"type\": \"doctype\"\n },\n {\n \"description\": \"Multiple Item prices.\",\n \"label\": \"Item Price\",\n \"name\": \"Item Price\",\n \"onboard\": 1,\n \"route\": \"#Report/Item Price\",\n \"type\": \"doctype\"\n },\n {\n \"description\": \"Price List master.\",\n \"label\": \"Price List\",\n \"name\": \"Price List\",\n \"onboard\": 1,\n \"type\": \"doctype\"\n },\n {\n \"description\": \"Bundle items at time of sale.\",\n \"label\": \"Product Bundle\",\n \"name\": \"Product Bundle\",\n \"type\": \"doctype\"\n },\n {\n \"description\": \"Tree of Item Groups.\",\n \"icon\": \"fa fa-sitemap\",\n \"label\": \"Item Group\",\n \"link\": \"Tree/Item Group\",\n \"name\": \"Item Group\",\n \"type\": \"doctype\"\n },\n {\n \"description\": \"Rules for applying different promotional schemes.\",\n \"label\": \"Promotional Scheme\",\n \"name\": \"Promotional Scheme\",\n \"type\": \"doctype\"\n },\n {\n \"description\": \"Rules for applying pricing and discount.\",\n \"label\": \"Pricing Rule\",\n \"name\": \"Pricing Rule\",\n \"type\": \"doctype\"\n }\n]"
},
{
"hidden": 0,
"label": "Items and Pricing",
"links": "[\n {\n \"description\": \"All Products or Services.\",\n \"label\": \"Item\",\n \"name\": \"Item\",\n \"onboard\": 1,\n \"type\": \"doctype\"\n },\n {\n \"description\": \"Multiple Item prices.\",\n \"label\": \"Item Price\",\n \"name\": \"Item Price\",\n \"onboard\": 1,\n \"route\": \"#Report/Item Price\",\n \"type\": \"doctype\"\n },\n {\n \"description\": \"Price List master.\",\n \"label\": \"Price List\",\n \"name\": \"Price List\",\n \"type\": \"doctype\"\n },\n {\n \"description\": \"Bundle items at time of sale.\",\n \"label\": \"Product Bundle\",\n \"name\": \"Product Bundle\",\n \"type\": \"doctype\"\n },\n {\n \"description\": \"Tree of Item Groups.\",\n \"icon\": \"fa fa-sitemap\",\n \"label\": \"Item Group\",\n \"link\": \"Tree/Item Group\",\n \"name\": \"Item Group\",\n \"type\": \"doctype\"\n },\n {\n \"description\": \"Rules for applying different promotional schemes.\",\n \"label\": \"Promotional Scheme\",\n \"name\": \"Promotional Scheme\",\n \"type\": \"doctype\"\n },\n {\n \"description\": \"Rules for applying pricing and discount.\",\n \"label\": \"Pricing Rule\",\n \"name\": \"Pricing Rule\",\n \"type\": \"doctype\"\n }\n]"
}, },
{ {
"hidden": 0, "hidden": 0,
"label": "Settings", "label": "Settings",
"links": "[\n {\n \"description\": \"Default settings for buying transactions.\",\n \"label\": \"Buying Settings\",\n \"name\": \"Buying Settings\",\n \"settings\": 1,\n \"type\": \"doctype\"\n },\n {\n \"description\": \"Tax template for buying transactions.\",\n \"label\": \"Purchase Taxes and Charges Template\",\n \"name\": \"Purchase Taxes and Charges Template\",\n \"type\": \"doctype\"\n },\n {\n \"description\": \"Template of terms or contract.\",\n \"label\": \"Terms and Conditions Template\",\n \"name\": \"Terms and Conditions\",\n \"type\": \"doctype\"\n }\n]" "links": "[\n {\n \"description\": \"Default settings for buying transactions.\",\n \"label\": \"Buying Settings\",\n \"name\": \"Buying Settings\",\n \"settings\": 1,\n \"type\": \"doctype\"\n },\n {\n \"description\": \"Tax template for buying transactions.\",\n \"label\": \"Purchase Taxes and Charges Template\",\n \"name\": \"Purchase Taxes and Charges Template\",\n \"type\": \"doctype\"\n },\n {\n \"description\": \"Template of terms or contract.\",\n \"label\": \"Terms and Conditions Template\",\n \"name\": \"Terms and Conditions\",\n \"type\": \"doctype\"\n }\n]"
}, },
{
"hidden": 0,
"label": "Supplier",
"links": "[\n {\n \"description\": \"Supplier database.\",\n \"label\": \"Supplier\",\n \"name\": \"Supplier\",\n \"onboard\": 1,\n \"type\": \"doctype\"\n },\n {\n \"description\": \"Supplier Group master.\",\n \"label\": \"Supplier Group\",\n \"name\": \"Supplier Group\",\n \"type\": \"doctype\"\n },\n {\n \"description\": \"All Contacts.\",\n \"label\": \"Contact\",\n \"name\": \"Contact\",\n \"type\": \"doctype\"\n },\n {\n \"description\": \"All Addresses.\",\n \"label\": \"Address\",\n \"name\": \"Address\",\n \"type\": \"doctype\"\n }\n]"
},
{ {
"hidden": 0, "hidden": 0,
"label": "Supplier Scorecard", "label": "Supplier Scorecard",
@ -28,67 +28,86 @@
{ {
"hidden": 0, "hidden": 0,
"label": "Key Reports", "label": "Key Reports",
"links": "[\n {\n \"is_query_report\": true,\n \"label\": \"Purchase Analytics\",\n \"name\": \"Purchase Analytics\",\n \"onboard\": 1,\n \"reference_doctype\": \"Purchase Order\",\n \"type\": \"report\"\n },\n {\n \"is_query_report\": true,\n \"label\": \"Supplier-Wise Sales Analytics\",\n \"name\": \"Supplier-Wise Sales Analytics\",\n \"onboard\": 1,\n \"reference_doctype\": \"Stock Ledger Entry\",\n \"type\": \"report\"\n },\n {\n \"is_query_report\": true,\n \"label\": \"Purchase Order Trends\",\n \"name\": \"Purchase Order Trends\",\n \"onboard\": 1,\n \"reference_doctype\": \"Purchase Order\",\n \"type\": \"report\"\n },\n {\n \"is_query_report\": true,\n \"label\": \"Procurement Tracker\",\n \"name\": \"Procurement Tracker\",\n \"onboard\": 1,\n \"reference_doctype\": \"Purchase Order\",\n \"type\": \"report\"\n },\n {\n \"is_query_report\": true,\n \"label\": \"Requested Items To Be Ordered\",\n \"name\": \"Requested Items To Be Ordered\",\n \"onboard\": 1,\n \"reference_doctype\": \"Material Request\",\n \"type\": \"report\"\n }\n]" "links": "[\n {\n \"is_query_report\": true,\n \"label\": \"Purchase Analytics\",\n \"name\": \"Purchase Analytics\",\n \"onboard\": 1,\n \"reference_doctype\": \"Purchase Order\",\n \"type\": \"report\"\n },\n {\n \"is_query_report\": true,\n \"label\": \"Purchase Order Analysis\",\n \"name\": \"Purchase Order Analysis\",\n \"onboard\": 1,\n \"reference_doctype\": \"Purchase Order\",\n \"type\": \"report\"\n },\n {\n \"is_query_report\": true,\n \"label\": \"Supplier-Wise Sales Analytics\",\n \"name\": \"Supplier-Wise Sales Analytics\",\n \"onboard\": 1,\n \"reference_doctype\": \"Stock Ledger Entry\",\n \"type\": \"report\"\n },\n {\n \"is_query_report\": true,\n \"label\": \"Requested Items to Order\",\n \"name\": \"Requested Items to Order\",\n \"onboard\": 1,\n \"reference_doctype\": \"Material Request\",\n \"type\": \"report\"\n },\n {\n \"is_query_report\": true,\n \"label\": \"Purchase Order Trends\",\n \"name\": \"Purchase Order Trends\",\n \"onboard\": 1,\n \"reference_doctype\": \"Purchase Order\",\n \"type\": \"report\"\n },\n {\n \"is_query_report\": true,\n \"label\": \"Procurement Tracker\",\n \"name\": \"Procurement Tracker\",\n \"onboard\": 1,\n \"reference_doctype\": \"Purchase Order\",\n \"type\": \"report\"\n }\n]"
}, },
{ {
"hidden": 0, "hidden": 0,
"label": "Other Reports", "label": "Other Reports",
"links": "[\n {\n \"is_query_report\": true,\n \"label\": \"Items To Be Requested\",\n \"name\": \"Items To Be Requested\",\n \"onboard\": 1,\n \"reference_doctype\": \"Item\",\n \"type\": \"report\"\n },\n {\n \"is_query_report\": true,\n \"label\": \"Item-wise Purchase History\",\n \"name\": \"Item-wise Purchase History\",\n \"onboard\": 1,\n \"reference_doctype\": \"Item\",\n \"type\": \"report\"\n },\n {\n \"is_query_report\": true,\n \"label\": \"Material Requests for which Supplier Quotations are not created\",\n \"name\": \"Material Requests for which Supplier Quotations are not created\",\n \"reference_doctype\": \"Material Request\",\n \"type\": \"report\"\n },\n {\n \"is_query_report\": true,\n \"label\": \"Supplier Addresses And Contacts\",\n \"name\": \"Address And Contacts\",\n \"reference_doctype\": \"Address\",\n \"route_options\": {\n \"party_type\": \"Supplier\"\n },\n \"type\": \"report\"\n }\n]" "links": "[\n {\n \"is_query_report\": true,\n \"label\": \"Items To Be Requested\",\n \"name\": \"Items To Be Requested\",\n \"onboard\": 1,\n \"reference_doctype\": \"Item\",\n \"type\": \"report\"\n },\n {\n \"is_query_report\": true,\n \"label\": \"Item-wise Purchase History\",\n \"name\": \"Item-wise Purchase History\",\n \"onboard\": 1,\n \"reference_doctype\": \"Item\",\n \"type\": \"report\"\n },\n {\n \"is_query_report\": true,\n \"label\": \"Subcontracted Raw Materials To Be Transferred\",\n \"name\": \"Subcontracted Raw Materials To Be Transferred\",\n \"reference_doctype\": \"Purchase Order\",\n \"type\": \"report\"\n },\n {\n \"is_query_report\": true,\n \"label\": \"Subcontracted Item To Be Received\",\n \"name\": \"Subcontracted Item To Be Received\",\n \"reference_doctype\": \"Purchase Order\",\n \"type\": \"report\"\n },\n {\n \"is_query_report\": true,\n \"label\": \"Quoted Item Comparison\",\n \"name\": \"Quoted Item Comparison\",\n \"onboard\": 1,\n \"reference_doctype\": \"Supplier Quotation\",\n \"type\": \"report\"\n },\n {\n \"is_query_report\": true,\n \"label\": \"Material Requests for which Supplier Quotations are not created\",\n \"name\": \"Material Requests for which Supplier Quotations are not created\",\n \"reference_doctype\": \"Material Request\",\n \"type\": \"report\"\n },\n {\n \"is_query_report\": true,\n \"label\": \"Supplier Addresses And Contacts\",\n \"name\": \"Address And Contacts\",\n \"reference_doctype\": \"Address\",\n \"route_options\": {\n \"party_type\": \"Supplier\"\n },\n \"type\": \"report\"\n }\n]"
},
{
"hidden": 0,
"label": "Regional",
"links": "[\n {\n \"description\": \"Import Italian Purchase Invoices\",\n \"label\": \"Import Supplier Invoice\",\n \"name\": \"Import Supplier Invoice\",\n \"type\": \"doctype\"\n } \n]"
} }
], ],
"cards_label": "",
"category": "Modules", "category": "Modules",
"charts": [ "charts": [
{ {
"chart_name": "Expenses", "chart_name": "Purchase Order Trends",
"label": "Expenses" "label": "Purchase Order Trends"
} }
], ],
"charts_label": "",
"creation": "2020-01-28 11:50:26.195467", "creation": "2020-01-28 11:50:26.195467",
"developer_mode_only": 0, "developer_mode_only": 0,
"disable_user_customization": 0, "disable_user_customization": 0,
"docstatus": 0, "docstatus": 0,
"doctype": "Desk Page", "doctype": "Desk Page",
"extends_another_page": 0, "extends_another_page": 0,
"icon": "", "hide_custom": 0,
"idx": 0, "idx": 0,
"is_standard": 1, "is_standard": 1,
"label": "Buying", "label": "Buying",
"modified": "2020-04-01 11:28:51.192097", "modified": "2020-05-28 13:32:49.960574",
"modified_by": "Administrator", "modified_by": "Administrator",
"module": "Buying", "module": "Buying",
"name": "Buying", "name": "Buying",
"onboarding": "Buying",
"owner": "Administrator", "owner": "Administrator",
"pin_to_bottom": 0, "pin_to_bottom": 0,
"pin_to_top": 0, "pin_to_top": 0,
"shortcuts": [ "shortcuts": [
{ {
"format": "{} Unpaid", "color": "#cef6d1",
"label": "Purchase Invoice", "format": "{} Available",
"link_to": "Purchase Invoice", "label": "Item",
"stats_filter": "{\n \"company\": [\"like\", '%' + frappe.defaults.get_global_default(\"company\") + '%'],\n \"status\": \"Unpaid\"\n}", "link_to": "Item",
"stats_filter": "{\n \"disabled\": 0\n}",
"type": "DocType" "type": "DocType"
}, },
{ {
"format": "{} to receive", "color": "#ffe8cd",
"format": "{} Pending",
"label": "Material Request",
"link_to": "Material Request",
"stats_filter": "{\n \"company\": [\"like\", '%' + frappe.defaults.get_global_default(\"company\") + '%'],\n \"status\": \"Pending\"\n}",
"type": "DocType"
},
{
"color": "#ffe8cd",
"format": "{} To Receive",
"label": "Purchase Order", "label": "Purchase Order",
"link_to": "Purchase Order", "link_to": "Purchase Order",
"stats_filter": "{\n \"company\": [\"like\", '%' + frappe.defaults.get_global_default(\"company\") + '%'],\n \"status\": \"To Receive\"\n}", "stats_filter": "{\n \"company\": [\"like\", '%' + frappe.defaults.get_global_default(\"company\") + '%'],\n \"status\":[\"in\", [\"To Receive\", \"To Receive and Bill\"]]\n}",
"type": "DocType" "type": "DocType"
}, },
{ {
"label": "Supplier Quotation", "label": "Purchase Analytics",
"link_to": "Supplier Quotation", "link_to": "Purchase Analytics",
"type": "DocType"
},
{
"label": "Accounts Payable",
"link_to": "Accounts Payable",
"type": "Report" "type": "Report"
}, },
{ {
"label": "Purchase Register", "label": "Purchase Order Analysis",
"link_to": "Purchase Register", "link_to": "Purchase Order Analysis",
"type": "Report" "type": "Report"
},
{
"label": "Dashboard",
"link_to": "Buying",
"type": "Dashboard"
} }
] ],
"shortcuts_label": ""
} }

View File

@ -6,3 +6,26 @@ frappe.ui.form.on('Buying Settings', {
// } // }
}); });
frappe.tour['Buying Settings'] = [
{
fieldname: "supp_master_name",
title: "Supplier Naming By",
description: __("By default, the Supplier Name is set as per the Supplier Name entered. If you want Suppliers to be named by a ") + "<a href='https://docs.erpnext.com/docs/user/manual/en/setting-up/settings/naming-series' target='_blank'>Naming Series</a>" + __(" choose the 'Naming Series' option."),
},
{
fieldname: "buying_price_list",
title: "Default Buying Price List",
description: __("Configure the default Price List when creating a new Purchase transaction. Item prices will be fetched from this Price List.")
},
{
fieldname: "po_required",
title: "Purchase Order Required for Purchase Invoice & Receipt Creation",
description: __("If this option is configured 'Yes', ERPNext will prevent you from creating a Purchase Invoice or Receipt without creating a Purchase Order first. This configuration can be overridden for a particular supplier by enabling the 'Allow Purchase Invoice Creation Without Purchase Order' checkbox in the Supplier master.")
},
{
fieldname: "pr_required",
title: "Purchase Receipt Required for Purchase Invoice Creation",
description: __("If this option is configured 'Yes', ERPNext will prevent you from creating a Purchase Invoice without creating a Purchase Receipt first. This configuration can be overridden for a particular supplier by enabling the 'Allow Purchase Invoice Creation Without Purchase Receipt' checkbox in the Supplier master.")
}
];

View File

@ -1,8 +1,10 @@
{ {
"actions": [],
"creation": "2013-06-25 11:04:03", "creation": "2013-06-25 11:04:03",
"description": "Settings for Buying Module", "description": "Settings for Buying Module",
"doctype": "DocType", "doctype": "DocType",
"document_type": "Other", "document_type": "Other",
"engine": "InnoDB",
"field_order": [ "field_order": [
"supp_master_name", "supp_master_name",
"supplier_group", "supplier_group",
@ -44,13 +46,13 @@
{ {
"fieldname": "po_required", "fieldname": "po_required",
"fieldtype": "Select", "fieldtype": "Select",
"label": "Purchase Order Required", "label": "Purchase Order Required for Purchase Invoice & Receipt Creation",
"options": "No\nYes" "options": "No\nYes"
}, },
{ {
"fieldname": "pr_required", "fieldname": "pr_required",
"fieldtype": "Select", "fieldtype": "Select",
"label": "Purchase Receipt Required", "label": "Purchase Receipt Required for Purchase Invoice Creation",
"options": "No\nYes" "options": "No\nYes"
}, },
{ {
@ -92,7 +94,8 @@
"icon": "fa fa-cog", "icon": "fa fa-cog",
"idx": 1, "idx": 1,
"issingle": 1, "issingle": 1,
"modified": "2019-08-20 13:13:09.055189", "links": [],
"modified": "2020-05-15 14:49:32.513611",
"modified_by": "Administrator", "modified_by": "Administrator",
"module": "Buying", "module": "Buying",
"name": "Buying Settings", "name": "Buying Settings",
@ -107,5 +110,7 @@
"share": 1, "share": 1,
"write": 1 "write": 1
} }
] ],
"sort_field": "modified",
"sort_order": "DESC"
} }

File diff suppressed because it is too large Load Diff

View File

@ -71,6 +71,15 @@ class PurchaseOrder(BuyingController):
"compare_fields": [["project", "="], ["item_code", "="], "compare_fields": [["project", "="], ["item_code", "="],
["uom", "="], ["conversion_factor", "="]], ["uom", "="], ["conversion_factor", "="]],
"is_child_table": True "is_child_table": True
},
"Material Request": {
"ref_dn_field": "material_request",
"compare_fields": [["company", "="]],
},
"Material Request Item": {
"ref_dn_field": "material_request_item",
"compare_fields": [["project", "="], ["item_code", "="]],
"is_child_table": True
} }
}) })

View File

@ -185,6 +185,23 @@ class TestPurchaseOrder(unittest.TestCase):
self.assertEquals(len(po.get('items')), 1) self.assertEquals(len(po.get('items')), 1)
self.assertEqual(po.status, 'To Receive and Bill') self.assertEqual(po.status, 'To Receive and Bill')
def test_update_child_qty_rate_perm(self):
po = create_purchase_order(item_code= "_Test Item", qty=4)
user = 'test@example.com'
test_user = frappe.get_doc('User', user)
test_user.add_roles("Accounts User")
frappe.set_user(user)
# update qty
trans_item = json.dumps([{'item_code' : '_Test Item', 'rate' : 200, 'qty' : 7, 'docname': po.items[0].name}])
self.assertRaises(frappe.ValidationError, update_child_qty_rate,'Purchase Order', trans_item, po.name)
# add new item
trans_item = json.dumps([{'item_code' : '_Test Item', 'rate' : 100, 'qty' : 2}])
self.assertRaises(frappe.ValidationError, update_child_qty_rate,'Purchase Order', trans_item, po.name)
frappe.set_user("Administrator")
def test_update_qty(self): def test_update_qty(self):
po = create_purchase_order() po = create_purchase_order()

View File

@ -25,6 +25,7 @@ class RequestforQuotation(BuyingController):
self.validate_duplicate_supplier() self.validate_duplicate_supplier()
self.validate_supplier_list() self.validate_supplier_list()
validate_for_items(self) validate_for_items(self)
super(RequestforQuotation, self).set_qty_as_per_stock_uom()
self.update_email_id() self.update_email_id()
def validate_duplicate_supplier(self): def validate_duplicate_supplier(self):
@ -278,6 +279,7 @@ def create_rfq_items(sq_doc, supplier, data):
"description": data.description, "description": data.description,
"qty": data.qty, "qty": data.qty,
"rate": data.rate, "rate": data.rate,
"conversion_factor": data.conversion_factor if data.conversion_factor else None,
"supplier_part_no": frappe.db.get_value("Item Supplier", {'parent': data.item_code, 'supplier': supplier}, "supplier_part_no"), "supplier_part_no": frappe.db.get_value("Item Supplier", {'parent': data.item_code, 'supplier': supplier}, "supplier_part_no"),
"warehouse": data.warehouse or '', "warehouse": data.warehouse or '',
"request_for_quotation_item": data.name, "request_for_quotation_item": data.name,

View File

@ -6,12 +6,14 @@ from __future__ import unicode_literals
import unittest import unittest
import frappe import frappe
from erpnext.templates.pages.rfq import check_supplier_has_docname_access
from frappe.utils import nowdate from frappe.utils import nowdate
from erpnext.stock.doctype.item.test_item import make_item
from erpnext.templates.pages.rfq import check_supplier_has_docname_access
from erpnext.buying.doctype.request_for_quotation.request_for_quotation import make_supplier_quotation
from erpnext.buying.doctype.request_for_quotation.request_for_quotation import create_supplier_quotation
class TestRequestforQuotation(unittest.TestCase): class TestRequestforQuotation(unittest.TestCase):
def test_quote_status(self): def test_quote_status(self):
from erpnext.buying.doctype.request_for_quotation.request_for_quotation import make_supplier_quotation
rfq = make_request_for_quotation() rfq = make_request_for_quotation()
self.assertEqual(rfq.get('suppliers')[0].quote_status, 'Pending') self.assertEqual(rfq.get('suppliers')[0].quote_status, 'Pending')
@ -31,7 +33,6 @@ class TestRequestforQuotation(unittest.TestCase):
self.assertEqual(rfq.get('suppliers')[1].quote_status, 'No Quote') self.assertEqual(rfq.get('suppliers')[1].quote_status, 'No Quote')
def test_make_supplier_quotation(self): def test_make_supplier_quotation(self):
from erpnext.buying.doctype.request_for_quotation.request_for_quotation import make_supplier_quotation
rfq = make_request_for_quotation() rfq = make_request_for_quotation()
sq = make_supplier_quotation(rfq.name, rfq.get('suppliers')[0].supplier) sq = make_supplier_quotation(rfq.name, rfq.get('suppliers')[0].supplier)
@ -51,15 +52,13 @@ class TestRequestforQuotation(unittest.TestCase):
self.assertEqual(sq1.get('items')[0].qty, 5) self.assertEqual(sq1.get('items')[0].qty, 5)
def test_make_supplier_quotation_with_special_characters(self): def test_make_supplier_quotation_with_special_characters(self):
from erpnext.buying.doctype.request_for_quotation.request_for_quotation import make_supplier_quotation
frappe.delete_doc_if_exists("Supplier", "_Test Supplier '1", force=1) frappe.delete_doc_if_exists("Supplier", "_Test Supplier '1", force=1)
supplier = frappe.new_doc("Supplier") supplier = frappe.new_doc("Supplier")
supplier.supplier_name = "_Test Supplier '1" supplier.supplier_name = "_Test Supplier '1"
supplier.supplier_group = "_Test Supplier Group" supplier.supplier_group = "_Test Supplier Group"
supplier.insert() supplier.insert()
rfq = make_request_for_quotation(supplier_wt_appos) rfq = make_request_for_quotation(supplier_data=supplier_wt_appos)
sq = make_supplier_quotation(rfq.name, supplier_wt_appos[0].get("supplier")) sq = make_supplier_quotation(rfq.name, supplier_wt_appos[0].get("supplier"))
sq.submit() sq.submit()
@ -76,7 +75,6 @@ class TestRequestforQuotation(unittest.TestCase):
frappe.form_dict.name = None frappe.form_dict.name = None
def test_make_supplier_quotation_from_portal(self): def test_make_supplier_quotation_from_portal(self):
from erpnext.buying.doctype.request_for_quotation.request_for_quotation import create_supplier_quotation
rfq = make_request_for_quotation() rfq = make_request_for_quotation()
rfq.get('items')[0].rate = 100 rfq.get('items')[0].rate = 100
rfq.supplier = rfq.suppliers[0].supplier rfq.supplier = rfq.suppliers[0].supplier
@ -90,12 +88,34 @@ class TestRequestforQuotation(unittest.TestCase):
self.assertEqual(supplier_quotation_doc.get('items')[0].qty, 5) self.assertEqual(supplier_quotation_doc.get('items')[0].qty, 5)
self.assertEqual(supplier_quotation_doc.get('items')[0].amount, 500) self.assertEqual(supplier_quotation_doc.get('items')[0].amount, 500)
def test_make_multi_uom_supplier_quotation(self):
item_code = "_Test Multi UOM RFQ Item"
if not frappe.db.exists('Item', item_code):
item = make_item(item_code, {'stock_uom': '_Test UOM'})
row = item.append('uoms', {
'uom': 'Kg',
'conversion_factor': 2
})
row.db_update()
def make_request_for_quotation(supplier_data=None): rfq = make_request_for_quotation(item_code="_Test Multi UOM RFQ Item", uom="Kg", conversion_factor=2)
rfq.get('items')[0].rate = 100
rfq.supplier = rfq.suppliers[0].supplier
self.assertEqual(rfq.items[0].stock_qty, 10)
supplier_quotation_name = create_supplier_quotation(rfq)
supplier_quotation = frappe.get_doc('Supplier Quotation', supplier_quotation_name)
self.assertEqual(supplier_quotation.items[0].qty, 5)
self.assertEqual(supplier_quotation.items[0].stock_qty, 10)
def make_request_for_quotation(**args):
""" """
:param supplier_data: List containing supplier data :param supplier_data: List containing supplier data
""" """
supplier_data = supplier_data if supplier_data else get_supplier_data() args = frappe._dict(args)
supplier_data = args.get("supplier_data") if args.get("supplier_data") else get_supplier_data()
rfq = frappe.new_doc('Request for Quotation') rfq = frappe.new_doc('Request for Quotation')
rfq.transaction_date = nowdate() rfq.transaction_date = nowdate()
rfq.status = 'Draft' rfq.status = 'Draft'
@ -106,11 +126,13 @@ def make_request_for_quotation(supplier_data=None):
rfq.append('suppliers', data) rfq.append('suppliers', data)
rfq.append("items", { rfq.append("items", {
"item_code": "_Test Item", "item_code": args.item_code or "_Test Item",
"description": "_Test Item", "description": "_Test Item",
"uom": "_Test UOM", "uom": args.uom or "_Test UOM",
"qty": 5, "stock_uom": args.stock_uom or "_Test UOM",
"warehouse": "_Test Warehouse - _TC", "qty": args.qty or 5,
"conversion_factor": args.conversion_factor or 1.0,
"warehouse": args.warehouse or "_Test Warehouse - _TC",
"schedule_date": nowdate() "schedule_date": nowdate()
}) })

View File

@ -1,4 +1,5 @@
{ {
"actions": [],
"autoname": "hash", "autoname": "hash",
"creation": "2016-02-25 08:04:02.452958", "creation": "2016-02-25 08:04:02.452958",
"doctype": "DocType", "doctype": "DocType",
@ -9,6 +10,7 @@
"supplier_part_no", "supplier_part_no",
"column_break_3", "column_break_3",
"item_name", "item_name",
"schedule_date",
"section_break_5", "section_break_5",
"description", "description",
"item_group", "item_group",
@ -18,9 +20,11 @@
"image_view", "image_view",
"quantity", "quantity",
"qty", "qty",
"stock_uom",
"col_break2", "col_break2",
"schedule_date",
"uom", "uom",
"conversion_factor",
"stock_qty",
"warehouse_and_reference", "warehouse_and_reference",
"warehouse", "warehouse",
"project_name", "project_name",
@ -33,7 +37,7 @@
"fields": [ "fields": [
{ {
"bold": 1, "bold": 1,
"columns": 3, "columns": 2,
"fieldname": "item_code", "fieldname": "item_code",
"fieldtype": "Link", "fieldtype": "Link",
"in_list_view": 1, "in_list_view": 1,
@ -98,7 +102,7 @@
{ {
"fieldname": "quantity", "fieldname": "quantity",
"fieldtype": "Section Break", "fieldtype": "Section Break",
"label": "Quantity" "label": "Quantity & Stock"
}, },
{ {
"bold": 1, "bold": 1,
@ -129,12 +133,12 @@
{ {
"fieldname": "uom", "fieldname": "uom",
"fieldtype": "Link", "fieldtype": "Link",
"in_list_view": 1,
"label": "UOM", "label": "UOM",
"oldfieldname": "uom", "oldfieldname": "uom",
"oldfieldtype": "Link", "oldfieldtype": "Link",
"options": "UOM", "options": "UOM",
"print_width": "100px", "print_width": "100px",
"read_only": 1,
"reqd": 1, "reqd": 1,
"width": "100px" "width": "100px"
}, },
@ -144,7 +148,7 @@
"label": "Warehouse and Reference" "label": "Warehouse and Reference"
}, },
{ {
"columns": 3, "columns": 2,
"fieldname": "warehouse", "fieldname": "warehouse",
"fieldtype": "Link", "fieldtype": "Link",
"in_list_view": 1, "in_list_view": 1,
@ -202,6 +206,7 @@
}, },
{ {
"allow_on_submit": 1, "allow_on_submit": 1,
"default": "0",
"fieldname": "page_break", "fieldname": "page_break",
"fieldtype": "Check", "fieldtype": "Check",
"label": "Page Break", "label": "Page Break",
@ -219,10 +224,36 @@
{ {
"fieldname": "section_break_23", "fieldname": "section_break_23",
"fieldtype": "Section Break" "fieldtype": "Section Break"
},
{
"fieldname": "stock_uom",
"fieldtype": "Link",
"label": "Stock UOM",
"options": "UOM",
"print_hide": 1,
"read_only": 1,
"reqd": 1
},
{
"fieldname": "conversion_factor",
"fieldtype": "Float",
"label": "UOM Conversion Factor",
"print_hide": 1,
"read_only": 1,
"reqd": 1
},
{
"fieldname": "stock_qty",
"fieldtype": "Float",
"label": "Qty as per Stock UOM",
"no_copy": 1,
"print_hide": 1,
"read_only": 1
} }
], ],
"istable": 1, "istable": 1,
"modified": "2019-05-01 17:50:23.703801", "links": [],
"modified": "2020-06-12 19:10:36.333441",
"modified_by": "Administrator", "modified_by": "Administrator",
"module": "Buying", "module": "Buying",
"name": "Request for Quotation Item", "name": "Request for Quotation Item",

View File

@ -761,7 +761,7 @@
"no_copy": 1, "no_copy": 1,
"oldfieldname": "status", "oldfieldname": "status",
"oldfieldtype": "Select", "oldfieldtype": "Select",
"options": "\nDraft\nSubmitted\nStopped\nCancelled", "options": "\nDraft\nSubmitted\nStopped\nCancelled\nExpired",
"print_hide": 1, "print_hide": 1,
"read_only": 1, "read_only": 1,
"reqd": 1, "reqd": 1,
@ -803,7 +803,7 @@
"idx": 29, "idx": 29,
"is_submittable": 1, "is_submittable": 1,
"links": [], "links": [],
"modified": "2020-04-15 11:44:52.958022", "modified": "2020-05-15 21:24:12.639482",
"modified_by": "Administrator", "modified_by": "Administrator",
"module": "Buying", "module": "Buying",
"name": "Supplier Quotation", "name": "Supplier Quotation",

View File

@ -0,0 +1,54 @@
{
"allow_roles": [
{
"role": "Purchase Manager"
},
{
"role": "Purchase User"
},
{
"role": "Stock Manager"
},
{
"role": "Stock User"
}
],
"creation": "2020-05-06 15:56:35.049205",
"docstatus": 0,
"doctype": "Module Onboarding",
"documentation_url": "https://docs.erpnext.com/docs/user/manual/en/buying",
"idx": 0,
"is_complete": 0,
"modified": "2020-06-01 12:55:09.234944",
"modified_by": "Administrator",
"module": "Buying",
"name": "Buying",
"owner": "Administrator",
"steps": [
{
"step": "Introduction to Buying"
},
{
"step": "Create a Supplier"
},
{
"step": "Setup your Warehouse"
},
{
"step": "Create a Product"
},
{
"step": "Create a Material Request"
},
{
"step": "Create your first Purchase Order"
},
{
"step": "Buying Settings"
}
],
"subtitle": "Products, Purchases, Analysis and more.",
"success_message": "The Buying Module is all set up!",
"title": "Let's Set Up the Buying Module.",
"user_can_dismiss": 1
}

View File

@ -0,0 +1,19 @@
{
"action": "Show Form Tour",
"creation": "2020-05-06 15:53:44.667414",
"docstatus": 0,
"doctype": "Onboarding Step",
"idx": 0,
"is_complete": 0,
"is_mandatory": 1,
"is_single": 1,
"is_skipped": 0,
"modified": "2020-06-01 12:52:57.668870",
"modified_by": "Administrator",
"name": "Buying Settings",
"owner": "Administrator",
"reference_document": "Buying Settings",
"show_full_form": 0,
"title": "Configure Buying Settings.",
"validate_action": 0
}

View File

@ -0,0 +1,19 @@
{
"action": "Create Entry",
"creation": "2020-05-15 14:39:09.818764",
"docstatus": 0,
"doctype": "Onboarding Step",
"idx": 0,
"is_complete": 0,
"is_mandatory": 1,
"is_single": 0,
"is_skipped": 0,
"modified": "2020-05-15 14:39:09.818764",
"modified_by": "Administrator",
"name": "Create a Material Request",
"owner": "Administrator",
"reference_document": "Material Request",
"show_full_form": 1,
"title": "Create a Material Request",
"validate_action": 1
}

Some files were not shown because too many files have changed in this diff Show More