Merge branch 'version-13-beta-pre-release' of https://github.com/frappe/erpnext into loan_amount_precision_v13

This commit is contained in:
Deepesh Garg 2020-06-07 21:32:50 +05:30
commit 221076c258
631 changed files with 529614 additions and 513998 deletions

View File

@ -1,6 +1,5 @@
dist: trusty
language: python
dist: trusty
git:
depth: 1
@ -14,21 +13,10 @@ addons:
jobs:
include:
- name: "Python 2.7 Server Side Test"
python: 2.7
script: bench --site test_site run-tests --app erpnext --coverage
- name: "Python 3.6 Server Side Test"
python: 3.6
script: bench --site test_site run-tests --app erpnext --coverage
- name: "Python 2.7 Patch Test"
python: 2.7
before_script:
- wget http://build.erpnext.com/20171108_190013_955977f8_database.sql.gz
- bench --site test_site --force restore ~/frappe-bench/20171108_190013_955977f8_database.sql.gz
script: bench --site test_site migrate
- name: "Python 3.6 Patch Test"
python: 3.6
before_script:
@ -40,8 +28,7 @@ install:
- cd ~
- nvm install 10
- git clone https://github.com/frappe/bench --depth 1
- pip install -e ./bench
- pip install frappe-bench
- git clone https://github.com/frappe/frappe --branch $TRAVIS_BRANCH --depth 1
- bench init --skip-assets --frappe-path ~/frappe --python $(which python) frappe-bench

View File

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

View File

@ -6,7 +6,7 @@ import frappe, json
from frappe import _
from frappe.utils import add_to_date, date_diff, getdate, nowdate, get_last_day, formatdate, get_link_to_form
from erpnext.accounts.report.general_ledger.general_ledger import execute
from frappe.core.page.dashboard.dashboard import cache_source, get_from_date_from_timespan
from frappe.utils.dashboard import cache_source, get_from_date_from_timespan
from frappe.desk.doctype.dashboard_chart.dashboard_chart import get_period_ending
from frappe.utils.nestedset import get_descendants_of
@ -14,7 +14,7 @@ from frappe.utils.nestedset import get_descendants_of
@frappe.whitelist()
@cache_source
def get(chart_name = None, chart = None, no_cache = None, filters = None, from_date = None,
to_date = None, timespan = None, time_interval = None):
to_date = None, timespan = None, time_interval = None, heatmap_year = None):
if chart_name:
chart = frappe.get_doc('Dashboard Chart', chart_name)
else:

View File

@ -0,0 +1,264 @@
# 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.utils import get_fiscal_year, get_account_name
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():
return frappe._dict({
"dashboards": get_dashboards(),
"charts": get_charts(),
"number_cards": get_number_cards()
})
def get_dashboards():
return [{
"name": "Accounts",
"dashboard_name": "Accounts",
"doctype": "Dashboard",
"charts": [
{ "chart": "Profit and Loss" , "width": "Full"},
{ "chart": "Incoming Bills (Purchase Invoice)", "width": "Half"},
{ "chart": "Outgoing Bills (Sales Invoice)", "width": "Half"},
{ "chart": "Accounts Receivable Ageing", "width": "Half"},
{ "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 = frappe.get_doc("Company", get_company_for_dashboards())
bank_account = company.default_bank_account or get_account_name("Bank", company=company.name)
fiscal_year = get_fiscal_year(date=nowdate())
default_cost_center = company.cost_center
return [
{
"doctype": "Dashboard Charts",
"name": "Profit and Loss",
"owner": "Administrator",
"report_name": "Profit and Loss Statement",
"filters_json": json.dumps({
"company": company.name,
"filter_based_on": "Fiscal Year",
"from_fiscal_year": fiscal_year[0],
"to_fiscal_year": fiscal_year[0],
"periodicity": "Monthly",
"include_default_book_entries": 1
}),
"type": "Bar",
'timeseries': 0,
"chart_type": "Report",
"chart_name": _("Profit and Loss"),
"is_custom": 1,
"is_public": 1
},
{
"doctype": "Dashboard Chart",
"time_interval": "Monthly",
"name": "Incoming Bills (Purchase Invoice)",
"chart_name": _("Incoming Bills (Purchase Invoice)"),
"timespan": "Last Year",
"color": "#a83333",
"value_based_on": "base_net_total",
"filters_json": json.dumps([["Purchase Invoice", "docstatus", "=", 1]]),
"chart_type": "Sum",
"timeseries": 1,
"based_on": "posting_date",
"owner": "Administrator",
"document_type": "Purchase Invoice",
"type": "Bar",
"width": "Half",
"is_public": 1
},
{
"doctype": "Dashboard Chart",
"name": "Outgoing Bills (Sales Invoice)",
"time_interval": "Monthly",
"chart_name": _("Outgoing Bills (Sales Invoice)"),
"timespan": "Last Year",
"color": "#7b933d",
"value_based_on": "base_net_total",
"filters_json": json.dumps([["Sales Invoice", "docstatus", "=", 1]]),
"chart_type": "Sum",
"timeseries": 1,
"based_on": "posting_date",
"owner": "Administrator",
"document_type": "Sales Invoice",
"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[0],
"to_fiscal_year": fiscal_year[0],
"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_number_cards():
fiscal_year = get_fiscal_year(date=nowdate())
year_start_date = get_date_str(fiscal_year[1])
year_end_date = get_date_str(fiscal_year[2])
return [
{
"doctype": "Number Card",
"document_type": "Payment Entry",
"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

@ -2,9 +2,10 @@ from __future__ import unicode_literals
import frappe
from frappe import _
from frappe.utils import date_diff, add_months, today, getdate, add_days, flt, get_last_day
from frappe.utils import date_diff, add_months, today, getdate, add_days, flt, get_last_day, cint, get_link_to_form
from erpnext.accounts.utils import get_account_currency
from frappe.email import sendmail_to_system_managers
from frappe.utils.background_jobs import enqueue
def validate_service_stop_date(doc):
''' Validates service_stop_date for Purchase Invoice and Sales Invoice '''
@ -32,8 +33,20 @@ def validate_service_stop_date(doc):
if old_stop_dates and old_stop_dates.get(item.name) and item.service_stop_date!=old_stop_dates.get(item.name):
frappe.throw(_("Cannot change Service Stop Date for item in row {0}").format(item.idx))
def convert_deferred_expense_to_expense(start_date=None, end_date=None):
def build_conditions(process_type, account, company):
conditions=''
deferred_account = "item.deferred_revenue_account" if process_type=="Income" else "item.deferred_expense_account"
if account:
conditions += "AND %s='%s'"%(deferred_account, account)
elif company:
conditions += "AND p.company='%s'"%(company)
return conditions
def convert_deferred_expense_to_expense(deferred_process, start_date=None, end_date=None, conditions=''):
# book the expense/income on the last day, but it will be trigger on the 1st of month at 12:00 AM
if not start_date:
start_date = add_months(today(), -1)
if not end_date:
@ -41,18 +54,25 @@ def convert_deferred_expense_to_expense(start_date=None, end_date=None):
# check for the purchase invoice for which GL entries has to be done
invoices = frappe.db.sql_list('''
select distinct parent from `tabPurchase Invoice Item`
where service_start_date<=%s and service_end_date>=%s
and enable_deferred_expense = 1 and docstatus = 1 and ifnull(amount, 0) > 0
''', (end_date, start_date))
select distinct item.parent
from `tabPurchase Invoice Item` item, `tabPurchase Invoice` p
where item.service_start_date<=%s and item.service_end_date>=%s
and item.enable_deferred_expense = 1 and item.parent=p.name
and item.docstatus = 1 and ifnull(item.amount, 0) > 0
{0}
'''.format(conditions), (end_date, start_date)) #nosec
# For each invoice, book deferred expense
for invoice in invoices:
doc = frappe.get_doc("Purchase Invoice", invoice)
book_deferred_income_or_expense(doc, end_date)
book_deferred_income_or_expense(doc, deferred_process, end_date)
def convert_deferred_revenue_to_income(start_date=None, end_date=None):
if frappe.flags.deferred_accounting_error:
send_mail(deferred_process)
def convert_deferred_revenue_to_income(deferred_process, start_date=None, end_date=None, conditions=''):
# book the expense/income on the last day, but it will be trigger on the 1st of month at 12:00 AM
if not start_date:
start_date = add_months(today(), -1)
if not end_date:
@ -60,14 +80,20 @@ def convert_deferred_revenue_to_income(start_date=None, end_date=None):
# check for the sales invoice for which GL entries has to be done
invoices = frappe.db.sql_list('''
select distinct parent from `tabSales Invoice Item`
where service_start_date<=%s and service_end_date>=%s
and enable_deferred_revenue = 1 and docstatus = 1 and ifnull(amount, 0) > 0
''', (end_date, start_date))
select distinct item.parent
from `tabSales Invoice Item` item, `tabSales Invoice` p
where item.service_start_date<=%s and item.service_end_date>=%s
and item.enable_deferred_revenue = 1 and item.parent=p.name
and item.docstatus = 1 and ifnull(item.amount, 0) > 0
{0}
'''.format(conditions), (end_date, start_date)) #nosec
for invoice in invoices:
doc = frappe.get_doc("Sales Invoice", invoice)
book_deferred_income_or_expense(doc, end_date)
book_deferred_income_or_expense(doc, deferred_process, end_date)
if frappe.flags.deferred_accounting_error:
send_mail(deferred_process)
def get_booking_dates(doc, item, posting_date=None):
if not posting_date:
@ -136,7 +162,7 @@ def calculate_amount(doc, item, last_gl_entry, total_days, total_booking_days, a
return amount, base_amount
def book_deferred_income_or_expense(doc, posting_date=None):
def book_deferred_income_or_expense(doc, deferred_process, posting_date=None):
enable_check = "enable_deferred_revenue" \
if doc.doctype=="Sales Invoice" else "enable_deferred_expense"
@ -159,7 +185,11 @@ def book_deferred_income_or_expense(doc, posting_date=None):
total_days, total_booking_days, account_currency)
make_gl_entries(doc, credit_account, debit_account, against,
amount, base_amount, end_date, project, account_currency, item.cost_center, item.name)
amount, base_amount, end_date, project, account_currency, item.cost_center, item, deferred_process)
# Returned in case of any errors because it tries to submit the same record again and again in case of errors
if frappe.flags.deferred_accounting_error:
return
if getdate(end_date) < getdate(posting_date) and not last_gl_entry:
_book_deferred_revenue_or_expense(item)
@ -169,8 +199,33 @@ def book_deferred_income_or_expense(doc, posting_date=None):
if item.get(enable_check):
_book_deferred_revenue_or_expense(item)
def process_deferred_accounting(posting_date=None):
''' Converts deferred income/expense into income/expense
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')):
return
start_date = add_months(today(), -1)
end_date = add_days(today(), -1)
for record_type in ('Income', 'Expense'):
doc = frappe.get_doc(dict(
doctype='Process Deferred Accounting',
posting_date=posting_date,
start_date=start_date,
end_date=end_date,
type=record_type
))
doc.insert()
doc.submit()
def make_gl_entries(doc, credit_account, debit_account, against,
amount, base_amount, posting_date, project, account_currency, cost_center, voucher_detail_no):
amount, base_amount, posting_date, project, account_currency, cost_center, item, deferred_process=None):
# GL Entry for crediting the amount in the deferred expense
from erpnext.accounts.general_ledger import make_gl_entries
@ -184,10 +239,12 @@ def make_gl_entries(doc, credit_account, debit_account, against,
"credit": base_amount,
"credit_in_account_currency": amount,
"cost_center": cost_center,
"voucher_detail_no": voucher_detail_no,
"voucher_detail_no": item.name,
'posting_date': posting_date,
'project': project
}, account_currency)
'project': project,
'against_voucher_type': 'Process Deferred Accounting',
'against_voucher': deferred_process
}, account_currency, item=item)
)
# GL Entry to debit the amount from the expense
gl_entries.append(
@ -197,10 +254,12 @@ def make_gl_entries(doc, credit_account, debit_account, against,
"debit": base_amount,
"debit_in_account_currency": amount,
"cost_center": cost_center,
"voucher_detail_no": voucher_detail_no,
"voucher_detail_no": item.name,
'posting_date': posting_date,
'project': project
}, account_currency)
'project': project,
'against_voucher_type': 'Process Deferred Accounting',
'against_voucher': deferred_process
}, account_currency, item=item)
)
if gl_entries:
@ -209,7 +268,16 @@ def make_gl_entries(doc, credit_account, debit_account, against,
frappe.db.commit()
except:
frappe.db.rollback()
title = _("Error while processing deferred accounting for {0}").format(doc.name)
traceback = frappe.get_traceback()
frappe.log_error(message=traceback , title=title)
sendmail_to_system_managers(title, traceback)
frappe.log_error(message=traceback)
frappe.flags.deferred_accounting_error = True
def send_mail(deferred_process):
title = _("Error while processing deferred accounting for {0}".format(deferred_process))
content = _("""
Deferred accounting failed for some invoices:
Please check Process Deferred Accounting {0}
and submit manually after resolving errors
""").format(get_link_to_form('Process Deferred Accounting', deferred_process))
sendmail_to_system_managers(title, content)

View File

@ -8,7 +8,7 @@
{
"hidden": 0,
"label": "General Ledger",
"links": "[\n {\n \"description\": \"Accounting journal entries.\",\n \"label\": \"Journal Entry\",\n \"name\": \"Journal Entry\",\n \"type\": \"doctype\"\n },\n {\n \"dependencies\": [\n \"GL Entry\"\n ],\n \"doctype\": \"GL Entry\",\n \"is_query_report\": true,\n \"label\": \"General Ledger\",\n \"name\": \"General Ledger\",\n \"type\": \"report\"\n },\n {\n \"dependencies\": [\n \"Sales Invoice\"\n ],\n \"doctype\": \"Sales Invoice\",\n \"is_query_report\": true,\n \"label\": \"Customer Ledger Summary\",\n \"name\": \"Customer Ledger Summary\",\n \"type\": \"report\"\n },\n {\n \"dependencies\": [\n \"Sales Invoice\"\n ],\n \"doctype\": \"Sales Invoice\",\n \"is_query_report\": true,\n \"label\": \"Supplier Ledger Summary\",\n \"name\": \"Supplier Ledger Summary\",\n \"type\": \"report\"\n }\n]"
"links": "[\n {\n \"description\": \"Accounting journal entries.\",\n \"label\": \"Journal Entry\",\n \"name\": \"Journal Entry\",\n \"type\": \"doctype\"\n },\n {\n \"description\": \"Make journal entries from a template.\",\n \"label\": \"Journal Entry Template\",\n \"name\": \"Journal Entry Template\",\n \"type\": \"doctype\"\n },\n \n {\n \"dependencies\": [\n \"GL Entry\"\n ],\n \"doctype\": \"GL Entry\",\n \"is_query_report\": true,\n \"label\": \"General Ledger\",\n \"name\": \"General Ledger\",\n \"type\": \"report\"\n },\n {\n \"dependencies\": [\n \"Sales Invoice\"\n ],\n \"doctype\": \"Sales Invoice\",\n \"is_query_report\": true,\n \"label\": \"Customer Ledger Summary\",\n \"name\": \"Customer Ledger Summary\",\n \"type\": \"report\"\n },\n {\n \"dependencies\": [\n \"Sales Invoice\"\n ],\n \"doctype\": \"Sales Invoice\",\n \"is_query_report\": true,\n \"label\": \"Supplier Ledger Summary\",\n \"name\": \"Supplier Ledger Summary\",\n \"type\": \"report\"\n }\n]"
},
{
"hidden": 0,
@ -18,7 +18,7 @@
{
"hidden": 0,
"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,
@ -45,11 +45,6 @@
"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]"
},
{
"hidden": 0,
"label": "Banking and Payments",
"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 Transaction Dates\",\n \"name\": \"Bank Reconciliation\",\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]"
},
{
"hidden": 0,
"label": "Subscription Management",
@ -89,8 +84,8 @@
"category": "Modules",
"charts": [
{
"chart_name": "Bank Balance",
"label": "Bank Balance"
"chart_name": "Profit and Loss",
"label": "Profit and Loss"
}
],
"creation": "2020-03-02 15:41:59.515192",
@ -99,23 +94,39 @@
"docstatus": 0,
"doctype": "Desk Page",
"extends_another_page": 0,
"icon": "",
"hide_custom": 0,
"idx": 0,
"is_standard": 1,
"label": "Accounting",
"modified": "2020-04-01 11:28:50.925719",
"modified": "2020-05-27 20:34:50.949772",
"modified_by": "Administrator",
"module": "Accounts",
"name": "Accounting",
"onboarding": "Accounts",
"owner": "Administrator",
"pin_to_bottom": 0,
"pin_to_top": 0,
"shortcuts": [
{
"label": "Account",
"label": "Chart Of Accounts",
"link_to": "Account",
"type": "DocType"
},
{
"label": "Sales Invoice",
"link_to": "Sales Invoice",
"type": "DocType"
},
{
"label": "Purchase Invoice",
"link_to": "Purchase Invoice",
"type": "DocType"
},
{
"label": "Dashboard",
"link_to": "Accounts",
"type": "Dashboard"
},
{
"label": "Journal Entry",
"link_to": "Journal Entry",
@ -136,11 +147,6 @@
"link_to": "General Ledger",
"type": "Report"
},
{
"label": "Profit and Loss Statement",
"link_to": "Profit and Loss Statement",
"type": "Report"
},
{
"label": "Trial Balance",
"link_to": "Trial Balance",

View File

@ -162,9 +162,9 @@ def toggle_disabling(doc):
def get_doctypes_with_dimensions():
doclist = ["GL Entry", "Sales Invoice", "Purchase Invoice", "Payment Entry", "Asset",
"Expense Claim", "Stock Entry", "Budget", "Payroll Entry", "Delivery Note", "Sales Invoice Item", "Purchase Invoice Item",
"Purchase Order Item", "Journal Entry Account", "Material Request Item", "Delivery Note Item", "Purchase Receipt Item",
"Stock Entry Detail", "Payment Entry Deduction", "Sales Taxes and Charges", "Purchase Taxes and Charges", "Shipping Rule",
"Expense Claim", "Expense Claim Detail", "Expense Taxes and Charges", "Stock Entry", "Budget", "Payroll Entry", "Delivery Note",
"Sales Invoice Item", "Purchase Invoice Item", "Purchase Order Item", "Journal Entry Account", "Material Request Item", "Delivery Note Item",
"Purchase Receipt Item", "Stock Entry Detail", "Payment Entry Deduction", "Sales Taxes and Charges", "Purchase Taxes and Charges", "Shipping Rule",
"Landed Cost Item", "Asset Value Adjustment", "Loyalty Program", "Fee Schedule", "Fee Structure", "Stock Reconciliation",
"Travel Request", "Fees", "POS Profile", "Opening Invoice Creation Tool", "Opening Invoice Creation Tool Item", "Subscription",
"Subscription Plan"]
@ -206,12 +206,13 @@ def get_dimension_filters():
WHERE disabled = 0
""", as_dict=1)
default_dimensions = frappe.db.sql("""SELECT parent, company, default_dimension
FROM `tabAccounting Dimension Detail`""", as_dict=1)
default_dimensions = frappe.db.sql("""SELECT p.fieldname, c.company, c.default_dimension
FROM `tabAccounting Dimension Detail` c, `tabAccounting Dimension` p
WHERE c.parent = p.name""", as_dict=1)
default_dimensions_map = {}
for dimension in default_dimensions:
default_dimensions_map.setdefault(dimension['company'], {})
default_dimensions_map[dimension['company']][dimension['parent']] = dimension['default_dimension']
default_dimensions_map.setdefault(dimension.company, {})
default_dimensions_map[dimension.company][dimension.fieldname] = dimension.default_dimension
return dimension_filters, default_dimensions_map

View File

@ -42,7 +42,7 @@ class AccountingPeriod(Document):
def get_doctypes_for_closing(self):
docs_for_closing = []
doctypes = ["Sales Invoice", "Purchase Invoice", "Journal Entry", "Payroll Entry", \
"Bank Reconciliation", "Asset", "Stock Entry"]
"Bank Clearance", "Asset", "Stock Entry"]
closed_doctypes = [{"document_type": doctype, "closed": 1} for doctype in doctypes]
for closed_doctype in closed_doctypes:
docs_for_closing.append(closed_doctype)

View File

@ -1,210 +1,226 @@
{
"creation": "2013-06-24 15:49:57",
"description": "Settings for Accounts",
"doctype": "DocType",
"document_type": "Other",
"editable_grid": 1,
"engine": "InnoDB",
"field_order": [
"auto_accounting_for_stock",
"acc_frozen_upto",
"frozen_accounts_modifier",
"determine_address_tax_category_from",
"over_billing_allowance",
"column_break_4",
"credit_controller",
"check_supplier_invoice_uniqueness",
"make_payment_via_journal_entry",
"unlink_payment_on_cancellation_of_invoice",
"unlink_advance_payment_on_cancelation_of_order",
"book_asset_depreciation_entry_automatically",
"allow_cost_center_in_entry_of_bs_account",
"add_taxes_from_item_tax_template",
"automatically_fetch_payment_terms",
"print_settings",
"show_inclusive_tax_in_print",
"column_break_12",
"show_payment_schedule_in_print",
"currency_exchange_section",
"allow_stale",
"stale_days",
"report_settings_sb",
"use_custom_cash_flow"
],
"fields": [
{
"default": "1",
"description": "If enabled, the system will post accounting entries for inventory automatically.",
"fieldname": "auto_accounting_for_stock",
"fieldtype": "Check",
"hidden": 1,
"in_list_view": 1,
"label": "Make Accounting Entry For Every Stock Movement"
},
{
"description": "Accounting entry frozen up to this date, nobody can do / modify entry except role specified below.",
"fieldname": "acc_frozen_upto",
"fieldtype": "Date",
"in_list_view": 1,
"label": "Accounts Frozen Upto"
},
{
"description": "Users with this role are allowed to set frozen accounts and create / modify accounting entries against frozen accounts",
"fieldname": "frozen_accounts_modifier",
"fieldtype": "Link",
"in_list_view": 1,
"label": "Role Allowed to Set Frozen Accounts & Edit Frozen Entries",
"options": "Role"
},
{
"default": "Billing Address",
"description": "Address used to determine Tax Category in transactions.",
"fieldname": "determine_address_tax_category_from",
"fieldtype": "Select",
"label": "Determine Address Tax Category From",
"options": "Billing Address\nShipping Address"
},
{
"fieldname": "column_break_4",
"fieldtype": "Column Break"
},
{
"description": "Role that is allowed to submit transactions that exceed credit limits set.",
"fieldname": "credit_controller",
"fieldtype": "Link",
"in_list_view": 1,
"label": "Credit Controller",
"options": "Role"
},
{
"fieldname": "check_supplier_invoice_uniqueness",
"fieldtype": "Check",
"label": "Check Supplier Invoice Number Uniqueness"
},
{
"fieldname": "make_payment_via_journal_entry",
"fieldtype": "Check",
"label": "Make Payment via Journal Entry"
},
{
"default": "1",
"fieldname": "unlink_payment_on_cancellation_of_invoice",
"fieldtype": "Check",
"label": "Unlink Payment on Cancellation of Invoice"
},
{
"default": "1",
"fieldname": "unlink_advance_payment_on_cancelation_of_order",
"fieldtype": "Check",
"label": "Unlink Advance Payment on Cancelation of Order"
},
{
"default": "1",
"fieldname": "book_asset_depreciation_entry_automatically",
"fieldtype": "Check",
"label": "Book Asset Depreciation Entry Automatically"
},
{
"fieldname": "allow_cost_center_in_entry_of_bs_account",
"fieldtype": "Check",
"label": "Allow Cost Center In Entry of Balance Sheet Account"
},
{
"default": "1",
"fieldname": "add_taxes_from_item_tax_template",
"fieldtype": "Check",
"label": "Automatically Add Taxes and Charges from Item Tax Template"
},
{
"fieldname": "print_settings",
"fieldtype": "Section Break",
"label": "Print Settings"
},
{
"fieldname": "show_inclusive_tax_in_print",
"fieldtype": "Check",
"label": "Show Inclusive Tax In Print"
},
{
"fieldname": "column_break_12",
"fieldtype": "Column Break"
},
{
"fieldname": "show_payment_schedule_in_print",
"fieldtype": "Check",
"label": "Show Payment Schedule in Print"
},
{
"fieldname": "currency_exchange_section",
"fieldtype": "Section Break",
"label": "Currency Exchange Settings"
},
{
"default": "1",
"fieldname": "allow_stale",
"fieldtype": "Check",
"in_list_view": 1,
"label": "Allow Stale Exchange Rates"
},
{
"default": "1",
"depends_on": "eval:doc.allow_stale==0",
"fieldname": "stale_days",
"fieldtype": "Int",
"label": "Stale Days"
},
{
"fieldname": "report_settings_sb",
"fieldtype": "Section Break",
"label": "Report Settings"
},
{
"default": "0",
"description": "Only select if you have setup Cash Flow Mapper documents",
"fieldname": "use_custom_cash_flow",
"fieldtype": "Check",
"label": "Use Custom Cash Flow Format"
},
{
"fieldname": "automatically_fetch_payment_terms",
"fieldtype": "Check",
"label": "Automatically Fetch Payment Terms"
},
{
"description": "Percentage you are allowed to bill more against the amount ordered. For example: If the order value is $100 for an item and tolerance is set as 10% then you are allowed to bill for $110.",
"fieldname": "over_billing_allowance",
"fieldtype": "Currency",
"label": "Over Billing Allowance (%)"
}
],
"icon": "icon-cog",
"idx": 1,
"issingle": 1,
"modified": "2019-07-04 18:20:55.789946",
"modified_by": "Administrator",
"module": "Accounts",
"name": "Accounts Settings",
"owner": "Administrator",
"permissions": [
{
"create": 1,
"email": 1,
"print": 1,
"read": 1,
"role": "Accounts Manager",
"share": 1,
"write": 1
},
{
"read": 1,
"role": "Sales User"
},
{
"read": 1,
"role": "Purchase User"
}
],
"quick_entry": 1,
"sort_order": "ASC",
"track_changes": 1
"actions": [],
"creation": "2013-06-24 15:49:57",
"description": "Settings for Accounts",
"doctype": "DocType",
"document_type": "Other",
"editable_grid": 1,
"engine": "InnoDB",
"field_order": [
"auto_accounting_for_stock",
"acc_frozen_upto",
"frozen_accounts_modifier",
"determine_address_tax_category_from",
"over_billing_allowance",
"column_break_4",
"credit_controller",
"check_supplier_invoice_uniqueness",
"make_payment_via_journal_entry",
"unlink_payment_on_cancellation_of_invoice",
"unlink_advance_payment_on_cancelation_of_order",
"book_asset_depreciation_entry_automatically",
"allow_cost_center_in_entry_of_bs_account",
"add_taxes_from_item_tax_template",
"automatically_fetch_payment_terms",
"automatically_process_deferred_accounting_entry",
"print_settings",
"show_inclusive_tax_in_print",
"column_break_12",
"show_payment_schedule_in_print",
"currency_exchange_section",
"allow_stale",
"stale_days",
"report_settings_sb",
"use_custom_cash_flow"
],
"fields": [
{
"default": "1",
"description": "If enabled, the system will post accounting entries for inventory automatically.",
"fieldname": "auto_accounting_for_stock",
"fieldtype": "Check",
"hidden": 1,
"in_list_view": 1,
"label": "Make Accounting Entry For Every Stock Movement"
},
{
"description": "Accounting entry frozen up to this date, nobody can do / modify entry except role specified below.",
"fieldname": "acc_frozen_upto",
"fieldtype": "Date",
"in_list_view": 1,
"label": "Accounts Frozen Upto"
},
{
"description": "Users with this role are allowed to set frozen accounts and create / modify accounting entries against frozen accounts",
"fieldname": "frozen_accounts_modifier",
"fieldtype": "Link",
"in_list_view": 1,
"label": "Role Allowed to Set Frozen Accounts & Edit Frozen Entries",
"options": "Role"
},
{
"default": "Billing Address",
"description": "Address used to determine Tax Category in transactions.",
"fieldname": "determine_address_tax_category_from",
"fieldtype": "Select",
"label": "Determine Address Tax Category From",
"options": "Billing Address\nShipping Address"
},
{
"fieldname": "column_break_4",
"fieldtype": "Column Break"
},
{
"description": "Role that is allowed to submit transactions that exceed credit limits set.",
"fieldname": "credit_controller",
"fieldtype": "Link",
"in_list_view": 1,
"label": "Credit Controller",
"options": "Role"
},
{
"default": "0",
"fieldname": "check_supplier_invoice_uniqueness",
"fieldtype": "Check",
"label": "Check Supplier Invoice Number Uniqueness"
},
{
"default": "0",
"fieldname": "make_payment_via_journal_entry",
"fieldtype": "Check",
"label": "Make Payment via Journal Entry"
},
{
"default": "1",
"fieldname": "unlink_payment_on_cancellation_of_invoice",
"fieldtype": "Check",
"label": "Unlink Payment on Cancellation of Invoice"
},
{
"default": "1",
"fieldname": "unlink_advance_payment_on_cancelation_of_order",
"fieldtype": "Check",
"label": "Unlink Advance Payment on Cancelation of Order"
},
{
"default": "1",
"fieldname": "book_asset_depreciation_entry_automatically",
"fieldtype": "Check",
"label": "Book Asset Depreciation Entry Automatically"
},
{
"default": "0",
"fieldname": "allow_cost_center_in_entry_of_bs_account",
"fieldtype": "Check",
"label": "Allow Cost Center In Entry of Balance Sheet Account"
},
{
"default": "1",
"fieldname": "add_taxes_from_item_tax_template",
"fieldtype": "Check",
"label": "Automatically Add Taxes and Charges from Item Tax Template"
},
{
"fieldname": "print_settings",
"fieldtype": "Section Break",
"label": "Print Settings"
},
{
"default": "0",
"fieldname": "show_inclusive_tax_in_print",
"fieldtype": "Check",
"label": "Show Inclusive Tax In Print"
},
{
"fieldname": "column_break_12",
"fieldtype": "Column Break"
},
{
"default": "0",
"fieldname": "show_payment_schedule_in_print",
"fieldtype": "Check",
"label": "Show Payment Schedule in Print"
},
{
"fieldname": "currency_exchange_section",
"fieldtype": "Section Break",
"label": "Currency Exchange Settings"
},
{
"default": "1",
"fieldname": "allow_stale",
"fieldtype": "Check",
"in_list_view": 1,
"label": "Allow Stale Exchange Rates"
},
{
"default": "1",
"depends_on": "eval:doc.allow_stale==0",
"fieldname": "stale_days",
"fieldtype": "Int",
"label": "Stale Days"
},
{
"fieldname": "report_settings_sb",
"fieldtype": "Section Break",
"label": "Report Settings"
},
{
"default": "0",
"description": "Only select if you have setup Cash Flow Mapper documents",
"fieldname": "use_custom_cash_flow",
"fieldtype": "Check",
"label": "Use Custom Cash Flow Format"
},
{
"default": "0",
"fieldname": "automatically_fetch_payment_terms",
"fieldtype": "Check",
"label": "Automatically Fetch Payment Terms"
},
{
"description": "Percentage you are allowed to bill more against the amount ordered. For example: If the order value is $100 for an item and tolerance is set as 10% then you are allowed to bill for $110.",
"fieldname": "over_billing_allowance",
"fieldtype": "Currency",
"label": "Over Billing Allowance (%)"
},
{
"default": "1",
"fieldname": "automatically_process_deferred_accounting_entry",
"fieldtype": "Check",
"label": "Automatically Process Deferred Accounting Entry"
}
],
"icon": "icon-cog",
"idx": 1,
"issingle": 1,
"links": [],
"modified": "2019-12-19 16:58:17.395595",
"modified_by": "Administrator",
"module": "Accounts",
"name": "Accounts Settings",
"owner": "Administrator",
"permissions": [
{
"create": 1,
"email": 1,
"print": 1,
"read": 1,
"role": "Accounts Manager",
"share": 1,
"write": 1
},
{
"read": 1,
"role": "Sales User"
},
{
"read": 1,
"role": "Purchase User"
}
],
"quick_entry": 1,
"sort_field": "modified",
"sort_order": "ASC",
"track_changes": 1
}

View File

@ -1,74 +1,32 @@
{
"allow_copy": 0,
"allow_guest_to_view": 0,
"allow_import": 0,
"allow_rename": 0,
"beta": 0,
"creation": "2018-04-16 21:50:05.860195",
"custom": 0,
"docstatus": 0,
"doctype": "DocType",
"document_type": "",
"editable_grid": 1,
"engine": "InnoDB",
"actions": [],
"creation": "2018-04-16 21:50:05.860195",
"doctype": "DocType",
"editable_grid": 1,
"engine": "InnoDB",
"field_order": [
"company"
],
"fields": [
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"default": "",
"fieldname": "company",
"fieldtype": "Link",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 1,
"in_standard_filter": 0,
"label": "Company",
"length": 0,
"no_copy": 0,
"options": "Company",
"permlevel": 0,
"precision": "",
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 1,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
"fieldname": "company",
"fieldtype": "Link",
"in_list_view": 1,
"label": "Company",
"options": "Company",
"reqd": 1
}
],
"has_web_view": 0,
"hide_heading": 0,
"hide_toolbar": 0,
"idx": 0,
"image_view": 0,
"in_create": 0,
"is_submittable": 0,
"issingle": 0,
"istable": 1,
"max_attachments": 0,
"modified": "2018-04-20 14:00:46.014502",
"modified_by": "Administrator",
"module": "Accounts",
"name": "Allowed To Transact With",
"name_case": "",
"owner": "Administrator",
"permissions": [],
"quick_entry": 1,
"read_only": 0,
"read_only_onload": 0,
"show_name_in_global_search": 0,
"sort_field": "modified",
"sort_order": "DESC",
"track_changes": 1,
"track_seen": 0
],
"istable": 1,
"links": [],
"modified": "2020-05-01 12:32:34.044911",
"modified_by": "Administrator",
"module": "Accounts",
"name": "Allowed To Transact With",
"owner": "Administrator",
"permissions": [],
"quick_entry": 1,
"sort_field": "modified",
"sort_order": "DESC",
"track_changes": 1
}

View File

@ -1,7 +1,7 @@
// Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors
// License: GNU General Public License v3. See license.txt
frappe.ui.form.on("Bank Reconciliation", {
frappe.ui.form.on("Bank Clearance", {
setup: function(frm) {
frm.add_fetch("account", "account_currency", "account_currency");
},

View File

@ -0,0 +1,130 @@
{
"allow_copy": 1,
"creation": "2013-01-10 16:34:05",
"doctype": "DocType",
"document_type": "Document",
"engine": "InnoDB",
"field_order": [
"account",
"account_currency",
"from_date",
"to_date",
"column_break_5",
"bank_account",
"include_reconciled_entries",
"include_pos_transactions",
"get_payment_entries",
"section_break_10",
"payment_entries",
"update_clearance_date",
"total_amount"
],
"fields": [
{
"fetch_from": "bank_account.account",
"fetch_if_empty": 1,
"fieldname": "account",
"fieldtype": "Link",
"in_list_view": 1,
"label": "Account",
"options": "Account",
"reqd": 1
},
{
"fieldname": "account_currency",
"fieldtype": "Link",
"hidden": 1,
"label": "Account Currency",
"options": "Currency",
"print_hide": 1
},
{
"fieldname": "from_date",
"fieldtype": "Date",
"in_list_view": 1,
"label": "From Date",
"reqd": 1
},
{
"fieldname": "to_date",
"fieldtype": "Date",
"in_list_view": 1,
"label": "To Date",
"reqd": 1
},
{
"fieldname": "column_break_5",
"fieldtype": "Column Break"
},
{
"description": "Select the Bank Account to reconcile.",
"fieldname": "bank_account",
"fieldtype": "Link",
"label": "Bank Account",
"options": "Bank Account"
},
{
"default": "0",
"fieldname": "include_reconciled_entries",
"fieldtype": "Check",
"in_list_view": 1,
"label": "Include Reconciled Entries"
},
{
"default": "0",
"fieldname": "include_pos_transactions",
"fieldtype": "Check",
"label": "Include POS Transactions"
},
{
"fieldname": "get_payment_entries",
"fieldtype": "Button",
"label": "Get Payment Entries"
},
{
"fieldname": "section_break_10",
"fieldtype": "Section Break"
},
{
"allow_bulk_edit": 1,
"fieldname": "payment_entries",
"fieldtype": "Table",
"label": "Payment Entries",
"options": "Bank Clearance Detail"
},
{
"fieldname": "update_clearance_date",
"fieldtype": "Button",
"label": "Update Clearance Date"
},
{
"fieldname": "total_amount",
"fieldtype": "Currency",
"label": "Total Amount",
"options": "account_currency",
"read_only": 1
}
],
"hide_toolbar": 1,
"icon": "fa fa-check",
"idx": 1,
"issingle": 1,
"modified": "2020-04-06 16:12:06.628008",
"modified_by": "Administrator",
"module": "Accounts",
"name": "Bank Clearance",
"owner": "Administrator",
"permissions": [
{
"create": 1,
"read": 1,
"role": "Accounts User",
"share": 1,
"write": 1
}
],
"quick_entry": 1,
"read_only": 1,
"sort_field": "modified",
"sort_order": "ASC"
}

View File

@ -11,7 +11,7 @@ form_grid_templates = {
"journal_entries": "templates/form_grid/bank_reconciliation_grid.html"
}
class BankReconciliation(Document):
class BankClearance(Document):
def get_payment_entries(self):
if not (self.from_date and self.to_date):
frappe.throw(_("From Date and To Date are Mandatory"))

View File

@ -0,0 +1,10 @@
# -*- coding: utf-8 -*-
# Copyright (c) 2020, Frappe Technologies Pvt. Ltd. and Contributors
# See license.txt
from __future__ import unicode_literals
# import frappe
import unittest
class TestBankClearance(unittest.TestCase):
pass

View File

@ -0,0 +1 @@
Detail of transaction for parent Bank Clearance.

View File

@ -326,7 +326,7 @@
"modified": "2019-01-07 16:52:07.174687",
"modified_by": "Administrator",
"module": "Accounts",
"name": "Bank Reconciliation Detail",
"name": "Bank Clearance Detail",
"owner": "Administrator",
"permissions": [],
"quick_entry": 1,

View File

@ -5,5 +5,5 @@ from __future__ import unicode_literals
import frappe
from frappe.model.document import Document
class BankReconciliationDetail(Document):
class BankClearanceDetail(Document):
pass

View File

@ -1,484 +0,0 @@
{
"allow_copy": 1,
"allow_events_in_timeline": 0,
"allow_guest_to_view": 0,
"allow_import": 0,
"allow_rename": 0,
"beta": 0,
"creation": "2013-01-10 16:34:05",
"custom": 0,
"docstatus": 0,
"doctype": "DocType",
"document_type": "Document",
"editable_grid": 0,
"fields": [
{
"allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fetch_from": "bank_account.account",
"fetch_if_empty": 1,
"fieldname": "account",
"fieldtype": "Link",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 1,
"in_standard_filter": 0,
"label": "Account",
"length": 0,
"no_copy": 0,
"options": "Account",
"permlevel": 0,
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 1,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fetch_if_empty": 0,
"fieldname": "account_currency",
"fieldtype": "Link",
"hidden": 1,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 0,
"label": "Account Currency",
"length": 0,
"no_copy": 0,
"options": "Currency",
"permlevel": 0,
"print_hide": 1,
"print_hide_if_no_value": 0,
"read_only": 0,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fetch_if_empty": 0,
"fieldname": "from_date",
"fieldtype": "Date",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 1,
"in_standard_filter": 0,
"label": "From Date",
"length": 0,
"no_copy": 0,
"permlevel": 0,
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 1,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fetch_if_empty": 0,
"fieldname": "to_date",
"fieldtype": "Date",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 1,
"in_standard_filter": 0,
"label": "To Date",
"length": 0,
"no_copy": 0,
"permlevel": 0,
"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_if_empty": 0,
"fieldname": "column_break_5",
"fieldtype": "Column Break",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 0,
"length": 0,
"no_copy": 0,
"permlevel": 0,
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"description": "Select the Bank Account to reconcile.",
"fetch_if_empty": 0,
"fieldname": "bank_account",
"fieldtype": "Link",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 0,
"label": "Bank Account",
"length": 0,
"no_copy": 0,
"options": "Bank Account",
"permlevel": 0,
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fetch_if_empty": 0,
"fieldname": "include_reconciled_entries",
"fieldtype": "Check",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 1,
"in_standard_filter": 0,
"label": "Include Reconciled Entries",
"length": 0,
"no_copy": 0,
"permlevel": 0,
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fetch_if_empty": 0,
"fieldname": "include_pos_transactions",
"fieldtype": "Check",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 0,
"label": "Include POS Transactions",
"length": 0,
"no_copy": 0,
"permlevel": 0,
"precision": "",
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fetch_if_empty": 0,
"fieldname": "get_payment_entries",
"fieldtype": "Button",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 0,
"label": "Get Payment Entries",
"length": 0,
"no_copy": 0,
"options": "",
"permlevel": 0,
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fetch_if_empty": 0,
"fieldname": "section_break_10",
"fieldtype": "Section Break",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 0,
"length": 0,
"no_copy": 0,
"permlevel": 0,
"precision": "",
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
},
{
"allow_bulk_edit": 1,
"allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fetch_if_empty": 0,
"fieldname": "payment_entries",
"fieldtype": "Table",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 0,
"label": "Payment Entries",
"length": 0,
"no_copy": 0,
"options": "Bank Reconciliation Detail",
"permlevel": 0,
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fetch_if_empty": 0,
"fieldname": "update_clearance_date",
"fieldtype": "Button",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 0,
"label": "Update Clearance Date",
"length": 0,
"no_copy": 0,
"options": "",
"permlevel": 0,
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fetch_if_empty": 0,
"fieldname": "total_amount",
"fieldtype": "Currency",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 0,
"label": "Total Amount",
"length": 0,
"no_copy": 0,
"options": "account_currency",
"permlevel": 0,
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 1,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
}
],
"has_web_view": 0,
"hide_toolbar": 1,
"icon": "fa fa-check",
"idx": 1,
"in_create": 0,
"is_submittable": 0,
"issingle": 1,
"istable": 0,
"max_attachments": 0,
"menu_index": 0,
"modified": "2020-01-22 00:00:00.000000",
"modified_by": "Administrator",
"module": "Accounts",
"name": "Bank Reconciliation",
"owner": "Administrator",
"permissions": [
{
"amend": 0,
"cancel": 0,
"create": 1,
"delete": 0,
"email": 0,
"export": 0,
"if_owner": 0,
"import": 0,
"permlevel": 0,
"print": 0,
"read": 1,
"report": 0,
"role": "Accounts User",
"set_user_permissions": 0,
"share": 1,
"submit": 0,
"write": 1
}
],
"quick_entry": 1,
"read_only": 1,
"show_name_in_global_search": 0,
"sort_order": "ASC",
"track_changes": 0,
"track_seen": 0,
"track_views": 0
}

View File

@ -1,22 +0,0 @@
QUnit.module('Account');
QUnit.test("test Bank Reconciliation", function(assert) {
assert.expect(0);
let done = assert.async();
frappe.run_serially([
() => frappe.set_route('Form', 'Bank Reconciliation'),
() => cur_frm.set_value('bank_account','Cash - FT'),
() => frappe.click_button('Get Payment Entries'),
() => {
for(var i=0;i<=cur_frm.doc.payment_entries.length-1;i++){
cur_frm.doc.payment_entries[i].clearance_date = frappe.datetime.add_days(frappe.datetime.now_date(), 2);
}
},
() => {cur_frm.refresh_fields('payment_entries');},
() => frappe.click_button('Update Clearance Date'),
() => frappe.timeout(0.5),
() => frappe.click_button('Close'),
() => done()
]);
});

View File

@ -1,8 +0,0 @@
# -*- coding: utf-8 -*-
# Copyright (c) 2018, Frappe Technologies Pvt. Ltd. and Contributors
# See license.txt
from __future__ import unicode_literals
import unittest
class TestBankReconciliation(unittest.TestCase):
pass

View File

@ -1 +0,0 @@
Detail of transaction for parent Bank Reconciliation.

View File

@ -1 +0,0 @@
from __future__ import unicode_literals

View File

@ -5,7 +5,7 @@ from __future__ import unicode_literals
import frappe
import unittest
from frappe.utils import nowdate
from frappe.utils import nowdate, now_datetime
from erpnext.accounts.utils import get_fiscal_year
from erpnext.buying.doctype.purchase_order.test_purchase_order import create_purchase_order
from erpnext.accounts.doctype.budget.budget import get_actual_expense, BudgetError
@ -13,27 +13,28 @@ from erpnext.accounts.doctype.journal_entry.test_journal_entry import make_journ
class TestBudget(unittest.TestCase):
def test_monthly_budget_crossed_ignore(self):
set_total_expense_zero("2013-02-28", "cost_center")
set_total_expense_zero(nowdate(), "cost_center")
budget = make_budget(budget_against="Cost Center")
jv = make_journal_entry("_Test Account Cost for Goods Sold - _TC",
"_Test Bank - _TC", 40000, "_Test Cost Center - _TC", posting_date="2013-02-28", submit=True)
"_Test Bank - _TC", 40000, "_Test Cost Center - _TC", posting_date=nowdate(), submit=True)
self.assertTrue(frappe.db.get_value("GL Entry",
{"voucher_type": "Journal Entry", "voucher_no": jv.name}))
budget.cancel()
jv.cancel()
def test_monthly_budget_crossed_stop1(self):
set_total_expense_zero("2013-02-28", "cost_center")
set_total_expense_zero(nowdate(), "cost_center")
budget = make_budget(budget_against="Cost Center")
frappe.db.set_value("Budget", budget.name, "action_if_accumulated_monthly_budget_exceeded", "Stop")
jv = make_journal_entry("_Test Account Cost for Goods Sold - _TC",
"_Test Bank - _TC", 40000, "_Test Cost Center - _TC", posting_date="2013-02-28")
"_Test Bank - _TC", 40000, "_Test Cost Center - _TC", posting_date=nowdate())
self.assertRaises(BudgetError, jv.submit)
@ -41,14 +42,14 @@ class TestBudget(unittest.TestCase):
budget.cancel()
def test_exception_approver_role(self):
set_total_expense_zero("2013-02-28", "cost_center")
set_total_expense_zero(nowdate(), "cost_center")
budget = make_budget(budget_against="Cost Center")
frappe.db.set_value("Budget", budget.name, "action_if_accumulated_monthly_budget_exceeded", "Stop")
jv = make_journal_entry("_Test Account Cost for Goods Sold - _TC",
"_Test Bank - _TC", 40000, "_Test Cost Center - _TC", posting_date="2013-03-02")
"_Test Bank - _TC", 40000, "_Test Cost Center - _TC", posting_date=nowdate())
self.assertRaises(BudgetError, jv.submit)
@ -112,16 +113,17 @@ class TestBudget(unittest.TestCase):
budget.load_from_db()
budget.cancel()
po.cancel()
def test_monthly_budget_crossed_stop2(self):
set_total_expense_zero("2013-02-28", "project")
set_total_expense_zero(nowdate(), "project")
budget = make_budget(budget_against="Project")
frappe.db.set_value("Budget", budget.name, "action_if_accumulated_monthly_budget_exceeded", "Stop")
jv = make_journal_entry("_Test Account Cost for Goods Sold - _TC",
"_Test Bank - _TC", 40000, "_Test Cost Center - _TC", project="_Test Project", posting_date="2013-02-28")
"_Test Bank - _TC", 40000, "_Test Cost Center - _TC", project="_Test Project", posting_date=nowdate())
self.assertRaises(BudgetError, jv.submit)
@ -129,86 +131,76 @@ class TestBudget(unittest.TestCase):
budget.cancel()
def test_yearly_budget_crossed_stop1(self):
set_total_expense_zero("2013-02-28", "cost_center")
set_total_expense_zero(nowdate(), "cost_center")
budget = make_budget(budget_against="Cost Center")
jv = make_journal_entry("_Test Account Cost for Goods Sold - _TC",
"_Test Bank - _TC", 150000, "_Test Cost Center - _TC", posting_date="2013-03-28")
"_Test Bank - _TC", 250000, "_Test Cost Center - _TC", posting_date=nowdate())
self.assertRaises(BudgetError, jv.submit)
budget.cancel()
def test_yearly_budget_crossed_stop2(self):
set_total_expense_zero("2013-02-28", "project")
set_total_expense_zero(nowdate(), "project")
budget = make_budget(budget_against="Project")
jv = make_journal_entry("_Test Account Cost for Goods Sold - _TC",
"_Test Bank - _TC", 150000, "_Test Cost Center - _TC", project="_Test Project", posting_date="2013-03-28")
"_Test Bank - _TC", 250000, "_Test Cost Center - _TC", project="_Test Project", posting_date=nowdate())
self.assertRaises(BudgetError, jv.submit)
budget.cancel()
def test_monthly_budget_on_cancellation1(self):
set_total_expense_zero("2013-02-28", "cost_center")
set_total_expense_zero(nowdate(), "cost_center")
budget = make_budget(budget_against="Cost Center")
jv1 = make_journal_entry("_Test Account Cost for Goods Sold - _TC",
"_Test Bank - _TC", 20000, "_Test Cost Center - _TC", posting_date="2013-02-28", submit=True)
for i in range(now_datetime().month):
jv = make_journal_entry("_Test Account Cost for Goods Sold - _TC",
"_Test Bank - _TC", 20000, "_Test Cost Center - _TC", posting_date=nowdate(), submit=True)
self.assertTrue(frappe.db.get_value("GL Entry",
{"voucher_type": "Journal Entry", "voucher_no": jv1.name}))
jv2 = make_journal_entry("_Test Account Cost for Goods Sold - _TC",
"_Test Bank - _TC", 20000, "_Test Cost Center - _TC", posting_date="2013-02-28", submit=True)
self.assertTrue(frappe.db.get_value("GL Entry",
{"voucher_type": "Journal Entry", "voucher_no": jv2.name}))
self.assertTrue(frappe.db.get_value("GL Entry",
{"voucher_type": "Journal Entry", "voucher_no": jv.name}))
frappe.db.set_value("Budget", budget.name, "action_if_accumulated_monthly_budget_exceeded", "Stop")
self.assertRaises(BudgetError, jv1.cancel)
self.assertRaises(BudgetError, jv.cancel)
budget.load_from_db()
budget.cancel()
def test_monthly_budget_on_cancellation2(self):
set_total_expense_zero("2013-02-28", "project")
set_total_expense_zero(nowdate(), "project")
budget = make_budget(budget_against="Project")
jv1 = make_journal_entry("_Test Account Cost for Goods Sold - _TC",
"_Test Bank - _TC", 20000, "_Test Cost Center - _TC", posting_date="2013-02-28", submit=True, project="_Test Project")
for i in range(now_datetime().month):
jv = make_journal_entry("_Test Account Cost for Goods Sold - _TC",
"_Test Bank - _TC", 20000, "_Test Cost Center - _TC", posting_date=nowdate(), submit=True, project="_Test Project")
self.assertTrue(frappe.db.get_value("GL Entry",
{"voucher_type": "Journal Entry", "voucher_no": jv1.name}))
jv2 = make_journal_entry("_Test Account Cost for Goods Sold - _TC",
"_Test Bank - _TC", 20000, "_Test Cost Center - _TC", posting_date="2013-02-28", submit=True, project="_Test Project")
self.assertTrue(frappe.db.get_value("GL Entry",
{"voucher_type": "Journal Entry", "voucher_no": jv2.name}))
self.assertTrue(frappe.db.get_value("GL Entry",
{"voucher_type": "Journal Entry", "voucher_no": jv.name}))
frappe.db.set_value("Budget", budget.name, "action_if_accumulated_monthly_budget_exceeded", "Stop")
self.assertRaises(BudgetError, jv1.cancel)
self.assertRaises(BudgetError, jv.cancel)
budget.load_from_db()
budget.cancel()
def test_monthly_budget_against_group_cost_center(self):
set_total_expense_zero("2013-02-28", "cost_center")
set_total_expense_zero("2013-02-28", "cost_center", "_Test Cost Center 2 - _TC")
set_total_expense_zero(nowdate(), "cost_center")
set_total_expense_zero(nowdate(), "cost_center", "_Test Cost Center 2 - _TC")
budget = make_budget(budget_against="Cost Center", cost_center="_Test Company - _TC")
frappe.db.set_value("Budget", budget.name, "action_if_accumulated_monthly_budget_exceeded", "Stop")
jv = make_journal_entry("_Test Account Cost for Goods Sold - _TC",
"_Test Bank - _TC", 40000, "_Test Cost Center 2 - _TC", posting_date="2013-02-28")
"_Test Bank - _TC", 40000, "_Test Cost Center 2 - _TC", posting_date=nowdate())
self.assertRaises(BudgetError, jv.submit)
@ -231,7 +223,7 @@ class TestBudget(unittest.TestCase):
frappe.db.set_value("Budget", budget.name, "action_if_accumulated_monthly_budget_exceeded", "Stop")
jv = make_journal_entry("_Test Account Cost for Goods Sold - _TC",
"_Test Bank - _TC", 40000, cost_center, posting_date="2013-02-28")
"_Test Bank - _TC", 40000, cost_center, posting_date=nowdate())
self.assertRaises(BudgetError, jv.submit)
@ -246,12 +238,14 @@ def set_total_expense_zero(posting_date, budget_against_field=None, budget_again
else:
budget_against = budget_against_CC or "_Test Cost Center - _TC"
fiscal_year = get_fiscal_year(nowdate())[0]
args = frappe._dict({
"account": "_Test Account Cost for Goods Sold - _TC",
"cost_center": "_Test Cost Center - _TC",
"monthly_end_date": posting_date,
"company": "_Test Company",
"fiscal_year": "_Test Fiscal Year 2013",
"fiscal_year": fiscal_year,
"budget_against_field": budget_against_field,
})
@ -263,10 +257,10 @@ def set_total_expense_zero(posting_date, budget_against_field=None, budget_again
if existing_expense:
if budget_against_field == "cost_center":
make_journal_entry("_Test Account Cost for Goods Sold - _TC",
"_Test Bank - _TC", -existing_expense, "_Test Cost Center - _TC", posting_date="2013-02-28", submit=True)
"_Test Bank - _TC", -existing_expense, "_Test Cost Center - _TC", posting_date=nowdate(), submit=True)
elif budget_against_field == "project":
make_journal_entry("_Test Account Cost for Goods Sold - _TC",
"_Test Bank - _TC", -existing_expense, "_Test Cost Center - _TC", submit=True, project="_Test Project", posting_date="2013-02-28")
"_Test Bank - _TC", -existing_expense, "_Test Cost Center - _TC", submit=True, project="_Test Project", posting_date=nowdate())
def make_budget(**args):
args = frappe._dict(args)
@ -274,10 +268,13 @@ def make_budget(**args):
budget_against=args.budget_against
cost_center=args.cost_center
fiscal_year = get_fiscal_year(nowdate())[0]
if budget_against == "Project":
budget_list = frappe.get_all("Budget", fields=["name"], filters = {"name": ("like", "_Test Project/_Test Fiscal Year 2013%")})
project_name = "{0}%".format("_Test Project/" + fiscal_year)
budget_list = frappe.get_all("Budget", fields=["name"], filters = {"name": ("like", project_name)})
else:
cost_center_name = "{0}%".format(cost_center or "_Test Cost Center - _TC/_Test Fiscal Year 2013")
cost_center_name = "{0}%".format(cost_center or "_Test Cost Center - _TC/" + fiscal_year)
budget_list = frappe.get_all("Budget", fields=["name"], filters = {"name": ("like", cost_center_name)})
for d in budget_list:
frappe.db.sql("delete from `tabBudget` where name = %(name)s", d)
@ -290,8 +287,10 @@ def make_budget(**args):
else:
budget.cost_center =cost_center or "_Test Cost Center - _TC"
monthly_distribution = frappe.get_doc("Monthly Distribution", "_Test Distribution")
monthly_distribution.fiscal_year = fiscal_year
budget.fiscal_year = "_Test Fiscal Year 2013"
budget.fiscal_year = fiscal_year
budget.monthly_distribution = "_Test Distribution"
budget.company = "_Test Company"
budget.applicable_on_booking_actual_expenses = 1
@ -300,7 +299,7 @@ def make_budget(**args):
budget.budget_against = budget_against
budget.append("accounts", {
"account": "_Test Account Cost for Goods Sold - _TC",
"budget_amount": 100000
"budget_amount": 200000
})
if args.applicable_on_material_request:

View File

@ -18,7 +18,7 @@ frappe.ui.form.on('Cost Center', {
},
refresh: function(frm) {
if (!frm.is_new()) {
frm.add_custom_button(__('Update Cost Center Number'), function () {
frm.add_custom_button(__('Update Cost Center Name / Number'), function () {
frm.trigger("update_cost_center_number");
});
}
@ -47,35 +47,45 @@ frappe.ui.form.on('Cost Center', {
},
update_cost_center_number: function(frm) {
var d = new frappe.ui.Dialog({
title: __('Update Cost Center Number'),
title: __('Update Cost Center Name / Number'),
fields: [
{
"label": 'Cost Center Number',
"label": "Cost Center Name",
"fieldname": "cost_center_name",
"fieldtype": "Data",
"reqd": 1,
"default": frm.doc.cost_center_name
},
{
"label": "Cost Center Number",
"fieldname": "cost_center_number",
"fieldtype": "Data",
"reqd": 1
"reqd": 1,
"default": frm.doc.cost_center_number
}
],
primary_action: function() {
var data = d.get_values();
if(data.cost_center_number === frm.doc.cost_center_number) {
if(data.cost_center_name === frm.doc.cost_center_name && data.cost_center_number === frm.doc.cost_center_number) {
d.hide();
return;
}
frappe.dom.freeze();
frappe.call({
method: "erpnext.accounts.utils.update_number_field",
method: "erpnext.accounts.utils.update_cost_center",
args: {
doctype_name: frm.doc.doctype,
name: frm.doc.name,
field_name: d.fields[0].fieldname,
number_value: data.cost_center_number,
docname: frm.doc.name,
cost_center_name: data.cost_center_name,
cost_center_number: data.cost_center_number,
company: frm.doc.company
},
callback: function(r) {
frappe.dom.unfreeze();
if(!r.exc) {
if(r.message) {
frappe.set_route("Form", "Cost Center", r.message);
} else {
me.frm.set_value("cost_center_name", data.cost_center_name);
me.frm.set_value("cost_center_number", data.cost_center_number);
}
d.hide();

View File

@ -2,7 +2,6 @@
"actions": [],
"allow_copy": 1,
"allow_import": 1,
"allow_rename": 1,
"creation": "2013-01-23 19:57:17",
"description": "Track separate Income and Expense for product verticals or divisions.",
"doctype": "DocType",
@ -126,7 +125,7 @@
"idx": 1,
"is_tree": 1,
"links": [],
"modified": "2020-03-18 17:59:04.321637",
"modified": "2020-04-29 16:09:30.025214",
"modified_by": "Administrator",
"module": "Accounts",
"name": "Cost Center",

View File

@ -1,4 +1,5 @@
{
"actions": [],
"autoname": "ACC-GLE-.YYYY.-.#####",
"creation": "2013-01-10 16:34:06",
"doctype": "DocType",
@ -30,7 +31,8 @@
"company",
"finance_book",
"to_rename",
"due_date"
"due_date",
"is_cancelled"
],
"fields": [
{
@ -245,12 +247,18 @@
"fieldname": "due_date",
"fieldtype": "Date",
"label": "Due Date"
},
{
"default": "0",
"fieldname": "is_cancelled",
"fieldtype": "Check",
"label": "Is Cancelled"
}
],
"icon": "fa fa-list",
"idx": 1,
"in_create": 1,
"modified": "2020-03-28 16:22:33.766994",
"modified": "2020-04-07 16:22:33.766994",
"modified_by": "Administrator",
"module": "Accounts",
"name": "GL Entry",

View File

@ -30,23 +30,20 @@ class GLEntry(Document):
self.pl_must_have_cost_center()
self.validate_cost_center()
if not self.flags.from_repost:
self.check_pl_account()
self.validate_party()
self.validate_currency()
self.check_pl_account()
self.validate_party()
self.validate_currency()
def on_update_with_args(self, adv_adj, update_outstanding = 'Yes', from_repost=False):
if not from_repost:
self.validate_account_details(adv_adj)
self.validate_dimensions_for_pl_and_bs()
check_freezing_date(self.posting_date, adv_adj)
def on_update_with_args(self, adv_adj, update_outstanding = 'Yes'):
self.validate_account_details(adv_adj)
self.validate_dimensions_for_pl_and_bs()
validate_frozen_account(self.account, adv_adj)
validate_balance_type(self.account, adv_adj)
# Update outstanding amt on against voucher
if self.against_voucher_type in ['Journal Entry', 'Sales Invoice', 'Purchase Invoice', 'Fees'] \
and self.against_voucher and update_outstanding == 'Yes' and not from_repost:
and self.against_voucher and update_outstanding == 'Yes':
update_outstanding_amt(self.account, self.party_type, self.party, self.against_voucher_type,
self.against_voucher)
@ -115,8 +112,8 @@ class GLEntry(Document):
from tabAccount where name=%s""", self.account, as_dict=1)[0]
if ret.is_group==1:
frappe.throw(_("{0} {1}: Account {2} cannot be a Group")
.format(self.voucher_type, self.voucher_no, self.account))
frappe.throw(_('''{0} {1}: Account {2} is a Group Account and group accounts cannot be used in
transactions''').format(self.voucher_type, self.voucher_no, self.account))
if ret.docstatus==2:
frappe.throw(_("{0} {1}: Account {2} is inactive")
@ -159,7 +156,6 @@ class GLEntry(Document):
if self.party_type and self.party:
validate_party_gle_currency(self.party_type, self.party, self.company, self.account_currency)
def validate_and_set_fiscal_year(self):
if not self.fiscal_year:
self.fiscal_year = get_fiscal_year(self.posting_date, company=self.company)[0]
@ -176,19 +172,6 @@ def validate_balance_type(account, adv_adj=False):
(balance_must_be=="Credit" and flt(balance) > 0):
frappe.throw(_("Balance for Account {0} must always be {1}").format(account, _(balance_must_be)))
def check_freezing_date(posting_date, adv_adj=False):
"""
Nobody can do GL Entries where posting date is before freezing date
except authorized person
"""
if not adv_adj:
acc_frozen_upto = frappe.db.get_value('Accounts Settings', None, 'acc_frozen_upto')
if acc_frozen_upto:
frozen_accounts_modifier = frappe.db.get_value( 'Accounts Settings', None,'frozen_accounts_modifier')
if getdate(posting_date) <= getdate(acc_frozen_upto) \
and not frozen_accounts_modifier in frappe.get_roles():
frappe.throw(_("You are not authorized to add or update entries before {0}").format(formatdate(acc_frozen_upto)))
def update_outstanding_amt(account, party_type, party, against_voucher_type, against_voucher, on_cancel=False):
if party_type and party:
party_condition = " and party_type={0} and party={1}"\

View File

@ -8,6 +8,7 @@ from frappe import _
from frappe.utils import flt, getdate, nowdate, add_days
from erpnext.controllers.accounts_controller import AccountsController
from erpnext.accounts.general_ledger import make_gl_entries
from erpnext.accounts.doctype.accounting_dimension.accounting_dimension import get_accounting_dimensions
class InvoiceDiscounting(AccountsController):
def validate(self):
@ -81,10 +82,15 @@ class InvoiceDiscounting(AccountsController):
def make_gl_entries(self):
company_currency = frappe.get_cached_value('Company', self.company, "default_currency")
gl_entries = []
invoice_fields = ["debit_to", "party_account_currency", "conversion_rate", "cost_center"]
accounting_dimensions = get_accounting_dimensions()
invoice_fields.extend(accounting_dimensions)
for d in self.invoices:
inv = frappe.db.get_value("Sales Invoice", d.sales_invoice,
["debit_to", "party_account_currency", "conversion_rate", "cost_center"], as_dict=1)
inv = frappe.db.get_value("Sales Invoice", d.sales_invoice, invoice_fields, as_dict=1)
if d.outstanding_amount:
outstanding_in_company_currency = flt(d.outstanding_amount * inv.conversion_rate,
@ -102,7 +108,7 @@ class InvoiceDiscounting(AccountsController):
"cost_center": inv.cost_center,
"against_voucher": d.sales_invoice,
"against_voucher_type": "Sales Invoice"
}, inv.party_account_currency))
}, inv.party_account_currency, item=inv))
gl_entries.append(self.get_gl_dict({
"account": self.accounts_receivable_credit,
@ -115,7 +121,7 @@ class InvoiceDiscounting(AccountsController):
"cost_center": inv.cost_center,
"against_voucher": d.sales_invoice,
"against_voucher_type": "Sales Invoice"
}, ar_credit_account_currency))
}, ar_credit_account_currency, item=inv))
make_gl_entries(gl_entries, cancel=(self.docstatus == 2), update_outstanding='No')

View File

@ -12,7 +12,6 @@ frappe.ui.form.on("Journal Entry", {
refresh: function(frm) {
erpnext.toggle_naming_series();
frm.cscript.voucher_type(frm.doc);
if(frm.doc.docstatus==1) {
frm.add_custom_button(__('Ledger'), function() {
@ -120,9 +119,78 @@ frappe.ui.form.on("Journal Entry", {
}
}
});
},
voucher_type: function(frm){
if(!frm.doc.company) return null;
if((!(frm.doc.accounts || []).length) || ((frm.doc.accounts || []).length === 1 && !frm.doc.accounts[0].account)) {
if(in_list(["Bank Entry", "Cash Entry"], frm.doc.voucher_type)) {
return frappe.call({
type: "GET",
method: "erpnext.accounts.doctype.journal_entry.journal_entry.get_default_bank_cash_account",
args: {
"account_type": (frm.doc.voucher_type=="Bank Entry" ?
"Bank" : (frm.doc.voucher_type=="Cash Entry" ? "Cash" : null)),
"company": frm.doc.company
},
callback: function(r) {
if(r.message) {
// If default company bank account not set
if(!$.isEmptyObject(r.message)){
update_jv_details(frm.doc, [r.message]);
}
}
}
});
}
else if(frm.doc.voucher_type=="Opening Entry") {
return frappe.call({
type:"GET",
method: "erpnext.accounts.doctype.journal_entry.journal_entry.get_opening_accounts",
args: {
"company": frm.doc.company
},
callback: function(r) {
frappe.model.clear_table(frm.doc, "accounts");
if(r.message) {
update_jv_details(frm.doc, r.message);
}
cur_frm.set_value("is_opening", "Yes");
}
});
}
}
},
from_template: function(frm){
if (frm.doc.from_template){
frappe.db.get_doc("Journal Entry Template", frm.doc.from_template)
.then((doc) => {
frappe.model.clear_table(frm.doc, "accounts");
frm.set_value({
"company": doc.company,
"voucher_type": doc.voucher_type,
"naming_series": doc.naming_series,
"is_opening": doc.is_opening,
"multi_currency": doc.multi_currency
})
update_jv_details(frm.doc, doc.accounts);
});
}
}
});
var update_jv_details = function(doc, r) {
$.each(r, function(i, d) {
var row = frappe.model.add_child(doc, "Journal Entry Account", "accounts");
row.account = d.account;
row.balance = d.balance;
});
refresh_field("accounts");
}
erpnext.accounts.JournalEntry = frappe.ui.form.Controller.extend({
onload: function() {
this.load_defaults();
@ -375,56 +443,6 @@ cur_frm.cscript.select_print_heading = function(doc,cdt,cdn){
cur_frm.pformat.print_heading = __("Journal Entry");
}
cur_frm.cscript.voucher_type = function(doc, cdt, cdn) {
cur_frm.set_df_property("cheque_no", "reqd", doc.voucher_type=="Bank Entry");
cur_frm.set_df_property("cheque_date", "reqd", doc.voucher_type=="Bank Entry");
if(!doc.company) return;
var update_jv_details = function(doc, r) {
$.each(r, function(i, d) {
var row = frappe.model.add_child(doc, "Journal Entry Account", "accounts");
row.account = d.account;
row.balance = d.balance;
});
refresh_field("accounts");
}
if((!(doc.accounts || []).length) || ((doc.accounts || []).length==1 && !doc.accounts[0].account)) {
if(in_list(["Bank Entry", "Cash Entry"], doc.voucher_type)) {
return frappe.call({
type: "GET",
method: "erpnext.accounts.doctype.journal_entry.journal_entry.get_default_bank_cash_account",
args: {
"account_type": (doc.voucher_type=="Bank Entry" ?
"Bank" : (doc.voucher_type=="Cash Entry" ? "Cash" : null)),
"company": doc.company
},
callback: function(r) {
if(r.message) {
update_jv_details(doc, [r.message]);
}
}
})
} else if(doc.voucher_type=="Opening Entry") {
return frappe.call({
type:"GET",
method: "erpnext.accounts.doctype.journal_entry.journal_entry.get_opening_accounts",
args: {
"company": doc.company
},
callback: function(r) {
frappe.model.clear_table(doc, "accounts");
if(r.message) {
update_jv_details(doc, r.message);
}
cur_frm.set_value("is_opening", "Yes")
}
})
}
}
}
frappe.ui.form.on("Journal Entry Account", {
party: function(frm, cdt, cdn) {
var d = frappe.get_doc(cdt, cdn);

View File

@ -1,4 +1,5 @@
{
"actions": [],
"allow_import": 1,
"autoname": "naming_series:",
"creation": "2013-03-25 10:53:52",
@ -10,10 +11,11 @@
"title",
"voucher_type",
"naming_series",
"column_break1",
"posting_date",
"company",
"finance_book",
"column_break1",
"from_template",
"company",
"posting_date",
"2_add_edit_gl_entries",
"accounts",
"section_break99",
@ -157,6 +159,7 @@
"in_global_search": 1,
"in_list_view": 1,
"label": "Reference Number",
"mandatory_depends_on": "eval:doc.voucher_type == \"Bank Entry\"",
"no_copy": 1,
"oldfieldname": "cheque_no",
"oldfieldtype": "Data",
@ -166,6 +169,7 @@
"fieldname": "cheque_date",
"fieldtype": "Date",
"label": "Reference Date",
"mandatory_depends_on": "eval:doc.voucher_type == \"Bank Entry\"",
"no_copy": 1,
"oldfieldname": "cheque_date",
"oldfieldtype": "Date",
@ -484,12 +488,22 @@
"options": "Journal Entry",
"print_hide": 1,
"read_only": 1
},
{
"fieldname": "from_template",
"fieldtype": "Link",
"label": "From Template",
"no_copy": 1,
"options": "Journal Entry Template",
"print_hide": 1,
"report_hide": 1
}
],
"icon": "fa fa-file-text",
"idx": 176,
"is_submittable": 1,
"modified": "2020-01-16 13:05:30.634226",
"links": [],
"modified": "2020-04-29 10:55:28.240916",
"modified_by": "Administrator",
"module": "Accounts",
"name": "Journal Entry",

View File

@ -57,6 +57,7 @@ class JournalEntry(AccountsController):
from erpnext.hr.doctype.salary_slip.salary_slip import unlink_ref_doc_from_salary_slip
unlink_ref_doc_from_payment_entries(self)
unlink_ref_doc_from_salary_slip(self.name)
self.ignore_linked_doctypes = ('GL Entry', 'Stock Ledger Entry')
self.make_gl_entries(1)
self.update_advance_paid()
self.update_expense_claim()
@ -559,20 +560,20 @@ class JournalEntry(AccountsController):
if self.write_off_based_on == 'Accounts Receivable':
jd1.party_type = "Customer"
jd1.credit = flt(d.outstanding_amount, self.precision("credit", "accounts"))
jd1.credit_in_account_currency = flt(d.outstanding_amount, self.precision("credit", "accounts"))
jd1.reference_type = "Sales Invoice"
jd1.reference_name = cstr(d.name)
elif self.write_off_based_on == 'Accounts Payable':
jd1.party_type = "Supplier"
jd1.debit = flt(d.outstanding_amount, self.precision("debit", "accounts"))
jd1.debit_in_account_currency = flt(d.outstanding_amount, self.precision("debit", "accounts"))
jd1.reference_type = "Purchase Invoice"
jd1.reference_name = cstr(d.name)
jd2 = self.append('accounts', {})
if self.write_off_based_on == 'Accounts Receivable':
jd2.debit = total
jd2.debit_in_account_currency = total
elif self.write_off_based_on == 'Accounts Payable':
jd2.credit = total
jd2.credit_in_account_currency = total
self.validate_total_debit_and_credit()
@ -594,7 +595,7 @@ class JournalEntry(AccountsController):
for d in self.accounts:
if d.reference_type=="Expense Claim" and d.reference_name:
doc = frappe.get_doc("Expense Claim", d.reference_name)
update_reimbursed_amount(doc)
update_reimbursed_amount(doc, jv=self.name)
def validate_expense_claim(self):

View File

@ -1,4 +1,5 @@
{
"actions": [],
"autoname": "hash",
"creation": "2013-02-22 01:27:39",
"doctype": "DocType",
@ -271,7 +272,8 @@
],
"idx": 1,
"istable": 1,
"modified": "2020-01-13 12:41:33.968025",
"links": [],
"modified": "2020-04-25 01:47:49.060128",
"modified_by": "Administrator",
"module": "Accounts",
"name": "Journal Entry Account",
@ -280,4 +282,4 @@
"sort_field": "modified",
"sort_order": "DESC",
"track_changes": 1
}
}

View File

@ -0,0 +1,91 @@
// Copyright (c) 2020, Frappe Technologies Pvt. Ltd. and contributors
// For license information, please see license.txt
frappe.ui.form.on("Journal Entry Template", {
setup: function(frm) {
frappe.model.set_default_values(frm.doc);
frm.set_query("account" ,"accounts", function(){
var filters = {
company: frm.doc.company,
is_group: 0
};
if(!frm.doc.multi_currency) {
$.extend(filters, {
account_currency: frappe.get_doc(":Company", frm.doc.company).default_currency
});
}
return { filters: filters };
});
frappe.call({
type: "GET",
method: "erpnext.accounts.doctype.journal_entry_template.journal_entry_template.get_naming_series",
callback: function(r){
if(r.message){
frm.set_df_property("naming_series", "options", r.message.split("\n"));
frm.set_value("naming_series", r.message.split("\n")[0]);
frm.refresh_field("naming_series");
}
}
});
},
voucher_type: function(frm) {
var add_accounts = function(doc, r) {
$.each(r, function(i, d) {
var row = frappe.model.add_child(doc, "Journal Entry Template Account", "accounts");
row.account = d.account;
});
refresh_field("accounts");
};
if(!frm.doc.company) return;
frm.trigger("clear_child");
switch(frm.doc.voucher_type){
case "Opening Entry":
frm.set_value("is_opening", "Yes");
frappe.call({
type:"GET",
method: "erpnext.accounts.doctype.journal_entry.journal_entry.get_opening_accounts",
args: {
"company": frm.doc.company
},
callback: function(r) {
if(r.message) {
add_accounts(frm.doc, r.message);
}
}
});
break;
case "Bank Entry":
case "Cash Entry":
frappe.call({
type: "GET",
method: "erpnext.accounts.doctype.journal_entry.journal_entry.get_default_bank_cash_account",
args: {
"account_type": (frm.doc.voucher_type=="Bank Entry" ?
"Bank" : (frm.doc.voucher_type=="Cash Entry" ? "Cash" : null)),
"company": frm.doc.company
},
callback: function(r) {
if(r.message) {
// If default company bank account not set
if(!$.isEmptyObject(r.message)){
add_accounts(frm.doc, [r.message]);
}
}
}
});
break;
default:
frm.trigger("clear_child");
}
},
clear_child: function(frm){
frappe.model.clear_table(frm.doc, "accounts");
frm.refresh_field("accounts");
}
});

View File

@ -0,0 +1,134 @@
{
"actions": [],
"autoname": "field:template_title",
"creation": "2020-04-09 01:32:51.332301",
"doctype": "DocType",
"document_type": "Document",
"editable_grid": 1,
"engine": "InnoDB",
"field_order": [
"section_break_1",
"template_title",
"voucher_type",
"naming_series",
"column_break_3",
"company",
"is_opening",
"multi_currency",
"section_break_3",
"accounts"
],
"fields": [
{
"fieldname": "section_break_1",
"fieldtype": "Section Break"
},
{
"fieldname": "voucher_type",
"fieldtype": "Select",
"in_list_view": 1,
"label": "Journal Entry Type",
"options": "Journal Entry\nInter Company Journal Entry\nBank Entry\nCash Entry\nCredit Card Entry\nDebit Note\nCredit Note\nContra Entry\nExcise Entry\nWrite Off Entry\nOpening Entry\nDepreciation Entry\nExchange Rate Revaluation",
"reqd": 1
},
{
"fieldname": "company",
"fieldtype": "Link",
"in_list_view": 1,
"in_standard_filter": 1,
"label": "Company",
"options": "Company",
"remember_last_selected_value": 1,
"reqd": 1
},
{
"fieldname": "column_break_3",
"fieldtype": "Column Break"
},
{
"default": "No",
"fieldname": "is_opening",
"fieldtype": "Select",
"label": "Is Opening",
"options": "No\nYes"
},
{
"fieldname": "accounts",
"fieldtype": "Table",
"label": "Accounting Entries",
"options": "Journal Entry Template Account"
},
{
"fieldname": "naming_series",
"fieldtype": "Select",
"label": "Series",
"no_copy": 1,
"print_hide": 1,
"reqd": 1,
"set_only_once": 1
},
{
"fieldname": "template_title",
"fieldtype": "Data",
"label": "Template Title",
"reqd": 1,
"unique": 1
},
{
"fieldname": "section_break_3",
"fieldtype": "Section Break"
},
{
"default": "0",
"fieldname": "multi_currency",
"fieldtype": "Check",
"label": "Multi Currency"
}
],
"links": [],
"modified": "2020-05-01 18:32:01.420488",
"modified_by": "Administrator",
"module": "Accounts",
"name": "Journal Entry Template",
"owner": "Administrator",
"permissions": [
{
"create": 1,
"delete": 1,
"email": 1,
"export": 1,
"print": 1,
"read": 1,
"report": 1,
"role": "Accounts User",
"share": 1,
"write": 1
},
{
"create": 1,
"delete": 1,
"email": 1,
"export": 1,
"print": 1,
"read": 1,
"report": 1,
"role": "Accounts Manager",
"share": 1,
"write": 1
},
{
"email": 1,
"export": 1,
"print": 1,
"read": 1,
"report": 1,
"role": "Auditor",
"share": 1
}
],
"search_fields": "voucher_type, company",
"sort_field": "modified",
"sort_order": "DESC",
"title_field": "template_title",
"track_changes": 1
}

View File

@ -0,0 +1,14 @@
# -*- 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 JournalEntryTemplate(Document):
pass
@frappe.whitelist()
def get_naming_series():
return frappe.get_meta("Journal Entry").get_field("naming_series").options

View File

@ -0,0 +1,10 @@
# -*- coding: utf-8 -*-
# Copyright (c) 2020, Frappe Technologies Pvt. Ltd. and Contributors
# See license.txt
from __future__ import unicode_literals
# import frappe
import unittest
class TestJournalEntryTemplate(unittest.TestCase):
pass

View File

@ -0,0 +1,31 @@
{
"actions": [],
"creation": "2020-04-09 01:48:42.783620",
"doctype": "DocType",
"editable_grid": 1,
"engine": "InnoDB",
"field_order": [
"account"
],
"fields": [
{
"fieldname": "account",
"fieldtype": "Link",
"in_list_view": 1,
"label": "Account",
"options": "Account",
"reqd": 1
}
],
"istable": 1,
"links": [],
"modified": "2020-04-25 01:15:44.879839",
"modified_by": "Administrator",
"module": "Accounts",
"name": "Journal Entry Template Account",
"owner": "Administrator",
"permissions": [],
"sort_field": "modified",
"sort_order": "DESC",
"track_changes": 1
}

View File

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

View File

@ -11,21 +11,9 @@ frappe.ui.form.on('Opening Invoice Creation Tool', {
};
});
frm.set_query('cost_center', 'invoices', function(doc, cdt, cdn) {
return {
filters: {
'company': doc.company
}
};
});
frm.set_query('cost_center', function(doc) {
return {
filters: {
'company': doc.company
}
};
});
if (frm.doc.company) {
frm.trigger('setup_company_filters');
}
},
refresh: function(frm) {
@ -51,19 +39,50 @@ frappe.ui.form.on('Opening Invoice Creation Tool', {
});
},
company: function(frm) {
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');
setup_company_filters: function(frm) {
frm.set_query('cost_center', 'invoices', function(doc, cdt, cdn) {
return {
filters: {
'company': doc.company
}
};
});
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) {

View File

@ -60,6 +60,7 @@ class PaymentEntry(AccountsController):
self.set_remarks()
self.validate_duplicate_entry()
self.validate_allocated_amount()
self.validate_paid_invoices()
self.ensure_supplier_is_not_blocked()
self.set_status()
@ -75,6 +76,7 @@ class PaymentEntry(AccountsController):
self.set_status()
def on_cancel(self):
self.ignore_linked_doctypes = ('GL Entry', 'Stock Ledger Entry')
self.setup_party_account_field()
self.make_gl_entries(cancel=1)
self.update_outstanding_amounts()
@ -84,7 +86,7 @@ class PaymentEntry(AccountsController):
self.update_payment_schedule(cancel=1)
self.set_payment_req_status()
self.set_status()
def set_payment_req_status(self):
from erpnext.accounts.doctype.payment_request.payment_request import update_payment_req_status
update_payment_req_status(self, None)
@ -226,6 +228,8 @@ class PaymentEntry(AccountsController):
valid_reference_doctypes = ("Purchase Order", "Purchase Invoice", "Journal Entry")
elif self.party_type == "Employee":
valid_reference_doctypes = ("Expense Claim", "Journal Entry", "Employee Advance")
elif self.party_type == "Shareholder":
valid_reference_doctypes = ("Journal Entry")
for d in self.get("references"):
if not d.allocated_amount:
@ -265,6 +269,25 @@ class PaymentEntry(AccountsController):
frappe.throw(_("{0} {1} must be submitted")
.format(d.reference_doctype, d.reference_name))
def validate_paid_invoices(self):
no_oustanding_refs = {}
for d in self.get("references"):
if not d.allocated_amount:
continue
if d.reference_doctype in ("Sales Invoice", "Purchase Invoice", "Fees"):
outstanding_amount, is_return = frappe.get_cached_value(d.reference_doctype, d.reference_name, ["outstanding_amount", "is_return"])
if outstanding_amount <= 0 and not is_return:
no_oustanding_refs.setdefault(d.reference_doctype, []).append(d)
for k, v in no_oustanding_refs.items():
frappe.msgprint(_("{} - {} now have {} as they had no outstanding amount left before submitting the Payment Entry.<br><br>\
If this is undesirable please cancel the corresponding Payment Entry.")
.format(k, frappe.bold(", ".join([d.reference_name for d in v])), frappe.bold("negative outstanding amount")),
title=_("Warning"), indicator="orange")
def validate_journal_entry(self):
for d in self.get("references"):
if d.allocated_amount and d.reference_doctype == "Journal Entry":
@ -428,8 +451,6 @@ class PaymentEntry(AccountsController):
frappe.throw(_("Reference No and Reference Date is mandatory for Bank transaction"))
def set_remarks(self):
if self.remarks: return
if self.payment_type=="Internal Transfer":
remarks = [_("Amount {0} {1} transferred from {2} to {3}")
.format(self.paid_from_account_currency, self.paid_amount, self.paid_from, self.paid_to)]
@ -483,7 +504,7 @@ class PaymentEntry(AccountsController):
"against": against_account,
"account_currency": self.party_account_currency,
"cost_center": self.cost_center
})
}, item=self)
dr_or_cr = "credit" if erpnext.get_party_account_type(self.party_type) == 'Receivable' else "debit"
@ -527,7 +548,7 @@ class PaymentEntry(AccountsController):
"credit_in_account_currency": self.paid_amount,
"credit": self.base_paid_amount,
"cost_center": self.cost_center
})
}, item=self)
)
if self.payment_type in ("Receive", "Internal Transfer"):
gl_entries.append(
@ -538,7 +559,7 @@ class PaymentEntry(AccountsController):
"debit_in_account_currency": self.received_amount,
"debit": self.base_received_amount,
"cost_center": self.cost_center
})
}, item=self)
)
def add_deductions_gl_entries(self, gl_entries):
@ -571,7 +592,7 @@ class PaymentEntry(AccountsController):
for d in self.get("references"):
if d.reference_doctype=="Expense Claim" and d.reference_name:
doc = frappe.get_doc("Expense Claim", d.reference_name)
update_reimbursed_amount(doc)
update_reimbursed_amount(doc, self.name)
def on_recurring(self, reference_doc, auto_repeat_doc):
self.reference_no = reference_doc.name

View File

@ -0,0 +1,12 @@
frappe.listview_settings['Payment Entry'] = {
onload: function(listview) {
listview.page.fields_dict.party_type.get_query = function() {
return {
"filters": {
"name": ["in", Object.keys(frappe.boot.party_account_types)],
}
};
};
}
};

View File

@ -35,8 +35,6 @@ class TestPaymentEntry(unittest.TestCase):
pe.cancel()
self.assertFalse(self.get_gle(pe.name))
so_advance_paid = frappe.db.get_value("Sales Order", so.name, "advance_paid")
self.assertEqual(so_advance_paid, 0)
@ -124,7 +122,6 @@ class TestPaymentEntry(unittest.TestCase):
self.assertEqual(outstanding_amount, 0)
pe.cancel()
self.assertFalse(self.get_gle(pe.name))
outstanding_amount = flt(frappe.db.get_value("Sales Invoice", si.name, "outstanding_amount"))
self.assertEqual(outstanding_amount, 100)
@ -381,7 +378,6 @@ class TestPaymentEntry(unittest.TestCase):
self.assertEqual(outstanding_amount, 0)
pe3.cancel()
self.assertFalse(self.get_gle(pe3.name))
outstanding_amount = flt(frappe.db.get_value("Sales Invoice", si1.name, "outstanding_amount"))
self.assertEqual(outstanding_amount, -100)

View File

@ -80,7 +80,7 @@ def make_journal_entry(doc, supplier, mode_of_payment=None):
paid_amt += d.amount
je.append('accounts', {
'account': doc.references[0].account,
'account': doc.account,
'credit_in_account_currency': paid_amt
})

View File

@ -1,4 +1,5 @@
{
"actions": [],
"autoname": "naming_series:",
"creation": "2015-12-15 22:23:24.745065",
"doctype": "DocType",
@ -210,13 +211,14 @@
"label": "IBAN"
},
{
"fetch_from": "bank_account.branch_code",
"fetch_from": "bank.branch_code",
"fetch_if_empty": 1,
"fieldname": "branch_code",
"fieldtype": "Read Only",
"label": "Branch Code"
},
{
"fetch_from": "bank_account.swift_number",
"fetch_from": "bank.swift_number",
"fieldname": "swift_number",
"fieldtype": "Read Only",
"label": "SWIFT Number"
@ -348,7 +350,8 @@
}
],
"is_submittable": 1,
"modified": "2020-03-28 16:07:31.960798",
"links": [],
"modified": "2020-05-08 10:23:02.815237",
"modified_by": "Administrator",
"module": "Accounts",
"name": "Payment Request",

View File

@ -69,7 +69,7 @@ class PaymentRequest(Document):
elif self.payment_request_type == 'Inward':
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)
if (hasattr(ref_doc, "order_type") and getattr(ref_doc, "order_type") == "Shopping Cart") \
@ -326,7 +326,7 @@ def make_payment_request(**args):
"reference_doctype": args.dt,
"reference_name": args.dn,
"party_type": args.get("party_type") or "Customer",
"party": args.get("party") or ref_doc.customer,
"party": args.get("party") or ref_doc.get("customer"),
"bank_account": bank_account
})
@ -420,7 +420,7 @@ def make_payment_entry(docname):
def update_payment_req_status(doc, method):
from erpnext.accounts.doctype.payment_entry.payment_entry import get_reference_details
for ref in doc.references:
payment_request_name = frappe.db.get_value("Payment Request",
{"reference_doctype": ref.reference_doctype, "reference_name": ref.reference_name,
@ -430,7 +430,7 @@ def update_payment_req_status(doc, method):
ref_details = get_reference_details(ref.reference_doctype, ref.reference_name, doc.party_account_currency)
pay_req_doc = frappe.get_doc('Payment Request', payment_request_name)
status = pay_req_doc.status
if status != "Paid" and not ref_details.outstanding_amount:
status = 'Paid'
elif status != "Partially Paid" and ref_details.outstanding_amount != ref_details.total_amount:

View File

@ -5,7 +5,7 @@ frappe.ui.form.on('Period Closing Voucher', {
onload: function(frm) {
if (!frm.doc.transaction_date) frm.doc.transaction_date = frappe.datetime.obj_to_str(new Date());
},
setup: function(frm) {
frm.set_query("closing_account_head", function() {
return {
@ -18,9 +18,9 @@ frappe.ui.form.on('Period Closing Voucher', {
}
});
},
refresh: function(frm) {
if(frm.doc.docstatus==1) {
if(frm.doc.docstatus > 0) {
frm.add_custom_button(__('Ledger'), function() {
frappe.route_options = {
"voucher_no": frm.doc.name,
@ -33,5 +33,5 @@ frappe.ui.form.on('Period Closing Voucher', {
}, "fa fa-table");
}
}
})

View File

@ -7,6 +7,8 @@ from frappe.utils import flt
from frappe import _
from erpnext.accounts.utils import get_account_currency
from erpnext.controllers.accounts_controller import AccountsController
from erpnext.accounts.doctype.accounting_dimension.accounting_dimension import (get_accounting_dimensions,
get_dimension_filters)
class PeriodClosingVoucher(AccountsController):
def validate(self):
@ -17,8 +19,9 @@ class PeriodClosingVoucher(AccountsController):
self.make_gl_entries()
def on_cancel(self):
frappe.db.sql("""delete from `tabGL Entry`
where voucher_type = 'Period Closing Voucher' and voucher_no=%s""", self.name)
self.ignore_linked_doctypes = ('GL Entry', 'Stock Ledger Entry')
from erpnext.accounts.general_ledger import make_reverse_gl_entries
make_reverse_gl_entries(voucher_type="Period Closing Voucher", voucher_no=self.name)
def validate_account_head(self):
closing_account_type = frappe.db.get_value("Account", self.closing_account_head, "root_type")
@ -49,7 +52,15 @@ class PeriodClosingVoucher(AccountsController):
def make_gl_entries(self):
gl_entries = []
net_pl_balance = 0
pl_accounts = self.get_pl_balances()
dimension_fields = ['t1.cost_center']
accounting_dimensions = get_accounting_dimensions()
for dimension in accounting_dimensions:
dimension_fields.append('t1.{0}'.format(dimension))
dimension_filters, default_dimensions = get_dimension_filters()
pl_accounts = self.get_pl_balances(dimension_fields)
for acc in pl_accounts:
if flt(acc.balance_in_company_currency):
@ -65,34 +76,41 @@ class PeriodClosingVoucher(AccountsController):
if flt(acc.balance_in_account_currency) > 0 else 0,
"credit": abs(flt(acc.balance_in_company_currency)) \
if flt(acc.balance_in_company_currency) > 0 else 0
}))
}, item=acc))
net_pl_balance += flt(acc.balance_in_company_currency)
if net_pl_balance:
cost_center = frappe.db.get_value("Company", self.company, "cost_center")
gl_entries.append(self.get_gl_dict({
gl_entry = self.get_gl_dict({
"account": self.closing_account_head,
"debit_in_account_currency": abs(net_pl_balance) if net_pl_balance > 0 else 0,
"debit": abs(net_pl_balance) if net_pl_balance > 0 else 0,
"credit_in_account_currency": abs(net_pl_balance) if net_pl_balance < 0 else 0,
"credit": abs(net_pl_balance) if net_pl_balance < 0 else 0,
"cost_center": cost_center
}))
})
for dimension in accounting_dimensions:
gl_entry.update({
dimension: default_dimensions.get(self.company, {}).get(dimension)
})
gl_entries.append(gl_entry)
from erpnext.accounts.general_ledger import make_gl_entries
make_gl_entries(gl_entries)
def get_pl_balances(self):
def get_pl_balances(self, dimension_fields):
"""Get balance for pl accounts"""
return frappe.db.sql("""
select
t1.account, t1.cost_center, t2.account_currency,
t1.account, t2.account_currency, {dimension_fields},
sum(t1.debit_in_account_currency) - sum(t1.credit_in_account_currency) as balance_in_account_currency,
sum(t1.debit) - sum(t1.credit) as balance_in_company_currency
from `tabGL Entry` t1, `tabAccount` t2
where t1.account = t2.name and t2.report_type = 'Profit and Loss'
and t2.docstatus < 2 and t2.company = %s
and t1.posting_date between %s and %s
group by t1.account, t1.cost_center
""", (self.company, self.get("year_start_date"), self.posting_date), as_dict=1)
group by t1.account, {dimension_fields}
""".format(dimension_fields = ', '.join(dimension_fields)), (self.company, self.get("year_start_date"), self.posting_date), as_dict=1)

View File

@ -1,123 +1,39 @@
{
"allow_copy": 0,
"allow_guest_to_view": 0,
"allow_import": 0,
"allow_rename": 0,
"beta": 0,
"creation": "2017-10-27 16:46:06.060930",
"custom": 0,
"docstatus": 0,
"doctype": "DocType",
"document_type": "",
"editable_grid": 1,
"engine": "InnoDB",
"actions": [],
"creation": "2017-10-27 16:46:06.060930",
"doctype": "DocType",
"editable_grid": 1,
"engine": "InnoDB",
"field_order": [
"default",
"user"
],
"fields": [
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "default",
"fieldtype": "Check",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 1,
"in_standard_filter": 0,
"label": "Default",
"length": 0,
"no_copy": 0,
"permlevel": 0,
"precision": "",
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"unique": 0
},
"default": "0",
"fieldname": "default",
"fieldtype": "Check",
"in_list_view": 1,
"label": "Default"
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "user",
"fieldtype": "Link",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 1,
"in_standard_filter": 0,
"label": "User",
"length": 0,
"no_copy": 0,
"options": "User",
"permlevel": 0,
"precision": "",
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"unique": 0
"fieldname": "user",
"fieldtype": "Link",
"in_list_view": 1,
"label": "User",
"options": "User"
}
],
"has_web_view": 0,
"hide_heading": 0,
"hide_toolbar": 0,
"idx": 0,
"image_view": 0,
"in_create": 0,
"is_submittable": 0,
"issingle": 0,
"istable": 0,
"max_attachments": 0,
"modified": "2017-11-23 17:13:16.005475",
"modified_by": "Administrator",
"module": "Accounts",
"name": "POS Profile User",
"name_case": "",
"owner": "Administrator",
"permissions": [
{
"amend": 0,
"apply_user_permissions": 0,
"cancel": 0,
"create": 1,
"delete": 1,
"email": 1,
"export": 1,
"if_owner": 0,
"import": 0,
"permlevel": 0,
"print": 1,
"read": 1,
"report": 1,
"role": "System Manager",
"set_user_permissions": 0,
"share": 1,
"submit": 0,
"write": 1
}
],
"quick_entry": 1,
"read_only": 0,
"read_only_onload": 0,
"show_name_in_global_search": 0,
"sort_field": "modified",
"sort_order": "DESC",
"track_changes": 1,
"track_seen": 0
],
"istable": 1,
"links": [],
"modified": "2020-05-01 09:46:47.599173",
"modified_by": "Administrator",
"module": "Accounts",
"name": "POS Profile User",
"owner": "Administrator",
"permissions": [],
"quick_entry": 1,
"sort_field": "modified",
"sort_order": "DESC",
"track_changes": 1
}

View File

@ -99,7 +99,7 @@ class PricingRule(Document):
self.same_item = 1
def validate_max_discount(self):
if self.rate_or_discount == "Discount Percentage" and self.items:
if self.rate_or_discount == "Discount Percentage" and self.get("items"):
for d in self.items:
max_discount = frappe.get_cached_value("Item", d.item_code, "max_discount")
if max_discount and flt(self.discount_percentage) > flt(max_discount):

View File

@ -4,13 +4,19 @@
# For license information, please see license.txt
from __future__ import unicode_literals
import frappe, copy, json
from frappe import throw, _
import copy
import json
from six import string_types
from frappe.utils import flt, cint, get_datetime, get_link_to_form, today
import frappe
from erpnext.setup.doctype.item_group.item_group import get_child_item_groups
from erpnext.stock.doctype.warehouse.warehouse import get_child_warehouses
from erpnext.stock.get_item_details import get_conversion_factor
from frappe import _, throw
from frappe.utils import cint, flt, get_datetime, get_link_to_form, getdate, today
class MultiplePricingRuleConflict(frappe.ValidationError): pass
@ -502,18 +508,16 @@ def get_pricing_rule_items(pr_doc):
return list(set(apply_on_data))
def validate_coupon_code(coupon_name):
from frappe.utils import today,getdate
coupon=frappe.get_doc("Coupon Code",coupon_name)
coupon = frappe.get_doc("Coupon Code", coupon_name)
if coupon.valid_from:
if coupon.valid_from > getdate(today()) :
frappe.throw(_("Sorry,coupon code validity has not started"))
if coupon.valid_from > getdate(today()):
frappe.throw(_("Sorry, this coupon code's validity has not started"))
elif coupon.valid_upto:
if coupon.valid_upto < getdate(today()) :
frappe.throw(_("Sorry,coupon code validity has expired"))
elif coupon.used>=coupon.maximum_use:
frappe.throw(_("Sorry,coupon code are exhausted"))
else:
return
if coupon.valid_upto < getdate(today()):
frappe.throw(_("Sorry, this coupon code's validity has expired"))
elif coupon.used >= coupon.maximum_use:
frappe.throw(_("Sorry, this coupon code is no longer valid"))
def update_coupon_code_count(coupon_name,transaction_type):
coupon=frappe.get_doc("Coupon Code",coupon_name)

View File

@ -0,0 +1,39 @@
// Copyright (c) 2019, Frappe Technologies Pvt. Ltd. and contributors
// For license information, please see license.txt
frappe.ui.form.on('Process Deferred Accounting', {
setup: function(frm) {
frm.set_query("document_type", function() {
return {
filters: {
'name': ['in', ['Sales Invoice', 'Purchase Invoice']]
}
};
});
},
validate: function() {
return new Promise((resolve) => {
return frappe.db.get_single_value('Accounts Settings', 'automatically_process_deferred_accounting_entry')
.then(value => {
if(value) {
frappe.throw(__('Manual entry cannot be created! Disable automatic entry for deferred accounting in accounts settings and try again'));
}
resolve(value);
});
});
},
end_date: function(frm) {
if (frm.doc.end_date && frm.doc.end_date < frm.doc.start_date) {
frappe.throw(__("End date cannot be before start date"));
}
},
onload: function(frm) {
if (frm.doc.posting_date && frm.doc.docstatus === 0) {
frm.set_value('start_date', frappe.datetime.add_months(frm.doc.posting_date, -1));
frm.set_value('end_date', frm.doc.posting_date);
}
}
});

View File

@ -0,0 +1,128 @@
{
"actions": [],
"autoname": "ACC-PDA-.#####",
"creation": "2019-11-04 18:01:23.454775",
"doctype": "DocType",
"editable_grid": 1,
"engine": "InnoDB",
"field_order": [
"company",
"type",
"account",
"column_break_3",
"posting_date",
"start_date",
"end_date",
"amended_from"
],
"fields": [
{
"fieldname": "type",
"fieldtype": "Select",
"in_list_view": 1,
"label": "Type",
"options": "\nIncome\nExpense",
"reqd": 1
},
{
"fieldname": "amended_from",
"fieldtype": "Link",
"label": "Amended From",
"no_copy": 1,
"options": "Process Deferred Accounting",
"print_hide": 1,
"read_only": 1
},
{
"fieldname": "start_date",
"fieldtype": "Date",
"in_list_view": 1,
"label": "Service Start Date",
"reqd": 1
},
{
"fieldname": "end_date",
"fieldtype": "Date",
"in_list_view": 1,
"label": "Service End Date",
"reqd": 1
},
{
"fieldname": "column_break_3",
"fieldtype": "Column Break"
},
{
"default": "Today",
"fieldname": "posting_date",
"fieldtype": "Date",
"in_list_view": 1,
"label": "Posting Date",
"reqd": 1
},
{
"fieldname": "account",
"fieldtype": "Link",
"label": "Account",
"options": "Account"
},
{
"fieldname": "company",
"fieldtype": "Link",
"label": "Company",
"options": "Company",
"reqd": 1
}
],
"is_submittable": 1,
"links": [],
"modified": "2020-02-06 18:18:09.852844",
"modified_by": "Administrator",
"module": "Accounts",
"name": "Process Deferred Accounting",
"owner": "Administrator",
"permissions": [
{
"cancel": 1,
"create": 1,
"delete": 1,
"email": 1,
"export": 1,
"print": 1,
"read": 1,
"report": 1,
"role": "System Manager",
"share": 1,
"submit": 1,
"write": 1
},
{
"cancel": 1,
"create": 1,
"delete": 1,
"email": 1,
"export": 1,
"print": 1,
"read": 1,
"report": 1,
"role": "Accounts Manager",
"share": 1,
"submit": 1,
"write": 1
},
{
"create": 1,
"delete": 1,
"email": 1,
"export": 1,
"print": 1,
"read": 1,
"report": 1,
"role": "Accounts User",
"share": 1,
"submit": 1,
"write": 1
}
],
"sort_field": "modified",
"sort_order": "DESC"
}

View File

@ -0,0 +1,34 @@
# -*- coding: utf-8 -*-
# Copyright (c) 2019, Frappe Technologies Pvt. Ltd. and contributors
# For license information, please see license.txt
from __future__ import unicode_literals
import frappe
import erpnext
from frappe import _
from frappe.model.document import Document
from erpnext.accounts.general_ledger import make_reverse_gl_entries
from erpnext.accounts.deferred_revenue import convert_deferred_expense_to_expense, \
convert_deferred_revenue_to_income, build_conditions
class ProcessDeferredAccounting(Document):
def validate(self):
if self.end_date < self.start_date:
frappe.throw(_("End date cannot be before start date"))
def on_submit(self):
conditions = build_conditions(self.type, self.account, self.company)
if self.type == 'Income':
convert_deferred_revenue_to_income(self.name, self.start_date, self.end_date, conditions)
else:
convert_deferred_expense_to_expense(self.name, self.start_date, self.end_date, conditions)
def on_cancel(self):
self.ignore_linked_doctypes = ['GL Entry']
gl_entries = frappe.get_all('GL Entry', fields = ['*'],
filters={
'against_voucher_type': self.doctype,
'against_voucher': self.name
})
make_reverse_gl_entries(gl_entries=gl_entries)

View File

@ -0,0 +1,48 @@
# -*- coding: utf-8 -*-
# Copyright (c) 2019, Frappe Technologies Pvt. Ltd. and Contributors
# See license.txt
from __future__ import unicode_literals
import frappe
import unittest
from erpnext.accounts.doctype.account.test_account import create_account
from erpnext.stock.doctype.item.test_item import create_item
from erpnext.accounts.doctype.sales_invoice.test_sales_invoice import create_sales_invoice, check_gl_entries
class TestProcessDeferredAccounting(unittest.TestCase):
def test_creation_of_ledger_entry_on_submit(self):
''' test creation of gl entries on submission of document '''
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()
process_deferred_accounting = doc = frappe.get_doc(dict(
doctype='Process Deferred Accounting',
posting_date="2019-01-01",
start_date="2019-01-01",
end_date="2019-01-31",
type="Income"
))
process_deferred_accounting.insert()
process_deferred_accounting.submit()
expected_gle = [
[deferred_account, 33.85, 0.0, "2019-01-31"],
["Sales - _TC", 0.0, 33.85, "2019-01-31"]
]
check_gl_entries(self, si.name, expected_gle, "2019-01-10")

View File

@ -382,11 +382,6 @@ function hide_fields(doc) {
cur_frm.refresh_fields();
}
cur_frm.cscript.update_stock = function(doc, dt, dn) {
hide_fields(doc, dt, dn);
this.frm.fields_dict.items.grid.toggle_reqd("item_code", doc.update_stock? true: false)
}
cur_frm.fields_dict.cash_bank_account.get_query = function(doc) {
return {
filters: [
@ -528,5 +523,10 @@ frappe.ui.form.on("Purchase Invoice", {
erpnext.buying.get_default_bom(frm);
}
frm.toggle_reqd("supplier_warehouse", frm.doc.is_subcontracted==="Yes");
},
update_stock: function(frm) {
hide_fields(frm.doc);
frm.fields_dict.items.grid.toggle_reqd("item_code", frm.doc.update_stock? true: false);
}
})

View File

@ -14,7 +14,7 @@ from erpnext.accounts.party import get_party_account, get_due_date
from erpnext.accounts.utils import get_account_currency, get_fiscal_year
from erpnext.stock.doctype.purchase_receipt.purchase_receipt import update_billed_amount_based_on_po
from erpnext.stock import get_warehouse_account_map
from erpnext.accounts.general_ledger import make_gl_entries, merge_similar_entries, delete_gl_entries
from erpnext.accounts.general_ledger import make_gl_entries, merge_similar_entries, make_reverse_gl_entries
from erpnext.accounts.doctype.gl_entry.gl_entry import update_outstanding_amt
from erpnext.buying.utils import check_on_hold_or_closed_status
from erpnext.accounts.general_ledger import get_round_off_account_and_cost_center
@ -382,7 +382,7 @@ class PurchaseInvoice(BuyingController):
self.update_project()
update_linked_doc(self.doctype, self.name, self.inter_company_invoice_reference)
def make_gl_entries(self, gl_entries=None, repost_future_gle=True, from_repost=False):
def make_gl_entries(self, gl_entries=None):
if not self.grand_total:
return
if not gl_entries:
@ -391,21 +391,17 @@ class PurchaseInvoice(BuyingController):
if gl_entries:
update_outstanding = "No" if (cint(self.is_paid) or self.write_off_account) else "Yes"
make_gl_entries(gl_entries, cancel=(self.docstatus == 2),
update_outstanding=update_outstanding, merge_entries=False, from_repost=from_repost)
if self.docstatus == 1:
make_gl_entries(gl_entries, update_outstanding=update_outstanding, merge_entries=False)
elif self.docstatus == 2:
make_reverse_gl_entries(voucher_type=self.doctype, voucher_no=self.name)
if update_outstanding == "No":
update_outstanding_amt(self.credit_to, "Supplier", self.supplier,
self.doctype, self.return_against if cint(self.is_return) and self.return_against else self.name)
if (repost_future_gle or self.flags.repost_future_gle) and cint(self.update_stock) and self.auto_accounting_for_stock:
from erpnext.controllers.stock_controller import update_gl_entries_after
items, warehouses = self.get_items_and_warehouses()
update_gl_entries_after(self.posting_date, self.posting_time,
warehouses, items, company = self.company)
elif self.docstatus == 2 and cint(self.update_stock) and self.auto_accounting_for_stock:
delete_gl_entries(voucher_type=self.doctype, voucher_no=self.name)
make_reverse_gl_entries(voucher_type=self.doctype, voucher_no=self.name)
def get_gl_entries(self, warehouse_account=None):
self.auto_accounting_for_stock = erpnext.is_perpetual_inventory_enabled(self.company)
@ -464,7 +460,7 @@ class PurchaseInvoice(BuyingController):
"against_voucher": self.return_against if cint(self.is_return) and self.return_against else self.name,
"against_voucher_type": self.doctype,
"cost_center": self.cost_center
}, self.party_account_currency)
}, self.party_account_currency, item=self)
)
def make_item_gl_entries(self, gl_entries):
@ -845,7 +841,7 @@ class PurchaseInvoice(BuyingController):
"against_voucher": self.return_against if cint(self.is_return) and self.return_against else self.name,
"against_voucher_type": self.doctype,
"cost_center": self.cost_center
}, self.party_account_currency)
}, self.party_account_currency, item=self)
)
gl_entries.append(
@ -856,7 +852,7 @@ class PurchaseInvoice(BuyingController):
"credit_in_account_currency": self.base_paid_amount \
if bank_account_currency==self.company_currency else self.paid_amount,
"cost_center": self.cost_center
}, bank_account_currency)
}, bank_account_currency, item=self)
)
def make_write_off_gl_entry(self, gl_entries):
@ -877,7 +873,7 @@ class PurchaseInvoice(BuyingController):
"against_voucher": self.return_against if cint(self.is_return) and self.return_against else self.name,
"against_voucher_type": self.doctype,
"cost_center": self.cost_center
}, self.party_account_currency)
}, self.party_account_currency, item=self)
)
gl_entries.append(
self.get_gl_dict({
@ -887,7 +883,7 @@ class PurchaseInvoice(BuyingController):
"credit_in_account_currency": self.base_write_off_amount \
if write_off_account_currency==self.company_currency else self.write_off_amount,
"cost_center": self.cost_center or self.write_off_cost_center
})
}, item=self)
)
def make_gle_for_rounding_adjustment(self, gl_entries):
@ -906,8 +902,7 @@ class PurchaseInvoice(BuyingController):
"debit_in_account_currency": self.rounding_adjustment,
"debit": self.base_rounding_adjustment,
"cost_center": self.cost_center or round_off_cost_center,
}
))
}, item=self))
def on_cancel(self):
super(PurchaseInvoice, self).on_cancel()
@ -934,6 +929,7 @@ class PurchaseInvoice(BuyingController):
frappe.db.set(self, 'status', 'Cancelled')
unlink_inter_company_doc(self.doctype, self.name, self.inter_company_invoice_reference)
self.ignore_linked_doctypes = ('GL Entry', 'Stock Ledger Entry')
def update_project(self):
project_list = []
@ -1024,6 +1020,40 @@ class PurchaseInvoice(BuyingController):
# calculate totals again after applying TDS
self.calculate_taxes_and_totals()
def set_status(self, update=False, status=None, update_modified=True):
if self.is_new():
if self.get('amended_from'):
self.status = 'Draft'
return
precision = self.precision("outstanding_amount")
outstanding_amount = flt(self.outstanding_amount, precision)
due_date = getdate(self.due_date)
nowdate = getdate()
if not status:
if self.docstatus == 2:
status = "Cancelled"
elif self.docstatus == 1:
if outstanding_amount > 0 and due_date < nowdate:
self.status = "Overdue"
elif outstanding_amount > 0 and due_date >= nowdate:
self.status = "Unpaid"
#Check if outstanding amount is 0 due to debit note issued against invoice
elif outstanding_amount <= 0 and self.is_return == 0 and frappe.db.get_value('Purchase Invoice', {'is_return': 1, 'return_against': self.name, 'docstatus': 1}):
self.status = "Debit Note Issued"
elif self.is_return == 1:
self.status = "Return"
elif outstanding_amount<=0:
self.status = "Paid"
else:
self.status = "Submitted"
else:
self.status = "Draft"
if update:
self.db_set('status', self.status, update_modified = update_modified)
def get_list_context(context=None):
from erpnext.controllers.website_list_for_contact import get_list_context

View File

@ -86,6 +86,8 @@ class TestPurchaseInvoice(unittest.TestCase):
pe.submit()
pi_doc = frappe.get_doc('Purchase Invoice', pi_doc.name)
pi_doc.load_from_db()
self.assertTrue(pi_doc.status, "Paid")
self.assertRaises(frappe.LinkExistsError, pi_doc.cancel)
unlink_payment_on_cancel_of_invoice()
@ -203,7 +205,9 @@ class TestPurchaseInvoice(unittest.TestCase):
pi.insert()
pi.submit()
pi.load_from_db()
self.assertTrue(pi.status, "Unpaid")
self.check_gle_for_pi(pi.name)
def check_gle_for_pi(self, pi):
@ -234,6 +238,9 @@ class TestPurchaseInvoice(unittest.TestCase):
pi = frappe.copy_doc(test_records[0])
pi.insert()
pi.load_from_db()
self.assertTrue(pi.status, "Draft")
pi.naming_series = 'TEST-'
self.assertRaises(frappe.CannotChangeConstantError, pi.save)
@ -248,6 +255,8 @@ class TestPurchaseInvoice(unittest.TestCase):
pi.get("taxes").pop(1)
pi.insert()
pi.submit()
pi.load_from_db()
self.assertTrue(pi.status, "Unpaid")
gl_entries = frappe.db.sql("""select account, debit, credit
from `tabGL Entry` where voucher_type='Purchase Invoice' and voucher_no=%s
@ -599,6 +608,11 @@ class TestPurchaseInvoice(unittest.TestCase):
# return entry
pi1 = make_purchase_invoice(is_return=1, return_against=pi.name, qty=-2, rate=50, update_stock=1)
pi.load_from_db()
self.assertTrue(pi.status, "Debit Note Issued")
pi1.load_from_db()
self.assertTrue(pi1.status, "Return")
actual_qty_2 = get_qty_after_transaction()
self.assertEqual(actual_qty_1 - 2, actual_qty_2)
@ -771,6 +785,8 @@ class TestPurchaseInvoice(unittest.TestCase):
from erpnext.accounts.doctype.sales_invoice.test_sales_invoice import get_outstanding_amount
pi = make_purchase_invoice(item_code = "_Test Item", qty = (5 * -1), rate=500, is_return = 1)
pi.load_from_db()
self.assertTrue(pi.status, "Return")
outstanding_amount = get_outstanding_amount(pi.doctype,
pi.name, "Creditors - _TC", pi.supplier, "Supplier")

View File

@ -138,13 +138,12 @@
"row_id": 7
}
],
"posting_date": "2013-02-03",
"supplier": "_Test Supplier",
"supplier_name": "_Test Supplier"
},
{
"bill_no": "NA",
"buying_price_list": "_Test Price List",
@ -204,7 +203,6 @@
"tax_amount": 150.0
}
],
"posting_date": "2013-02-03",
"supplier": "_Test Supplier",
"supplier_name": "_Test Supplier"
}

View File

@ -26,16 +26,24 @@ frappe.ui.form.on("Sales Invoice", {
&& !frm.doc.is_return && !frm.doc.ewaybill) {
frm.add_custom_button('E-Way Bill JSON', () => {
var w = window.open(
frappe.urllib.get_full_url(
"/api/method/erpnext.regional.india.utils.generate_ewb_json?"
+ "dt=" + encodeURIComponent(frm.doc.doctype)
+ "&dn=" + encodeURIComponent(frm.doc.name)
)
);
if (!w) {
frappe.msgprint(__("Please enable pop-ups")); return;
}
frappe.call({
method: 'erpnext.regional.india.utils.generate_ewb_json',
args: {
'dt': frm.doc.doctype,
'dn': [frm.doc.name]
},
callback: function(r) {
if (r.message) {
const args = {
cmd: 'erpnext.regional.india.utils.download_ewb_json',
data: r.message,
docname: frm.doc.name
};
open_url_post(frappe.request.url, args);
}
}
});
}, __("Create"));
}
}

View File

@ -16,17 +16,23 @@ frappe.listview_settings['Sales Invoice'].onload = function (doclist) {
}
}
var w = window.open(
frappe.urllib.get_full_url(
"/api/method/erpnext.regional.india.utils.generate_ewb_json?"
+ "dt=" + encodeURIComponent(doclist.doctype)
+ "&dn=" + encodeURIComponent(docnames)
)
);
if (!w) {
frappe.msgprint(__("Please enable pop-ups")); return;
}
frappe.call({
method: 'erpnext.regional.india.utils.generate_ewb_json',
args: {
'dt': doclist.doctype,
'dn': docnames
},
callback: function(r) {
if (r.message) {
const args = {
cmd: 'erpnext.regional.india.utils.download_ewb_json',
data: r.message,
docname: docnames
};
open_url_post(frappe.request.url, args);
}
}
});
};
doclist.page.add_actions_menu_item(__('Generate E-Way Bill JSON'), action, false);

View File

@ -345,7 +345,7 @@ erpnext.accounts.SalesInvoiceController = erpnext.selling.SellingController.exte
set_dynamic_labels: function() {
this._super();
this.hide_fields(this.frm.doc);
this.frm.events.hide_fields(this.frm)
},
items_on_form_rendered: function() {
@ -404,7 +404,7 @@ erpnext.accounts.SalesInvoiceController = erpnext.selling.SellingController.exte
if(r.message && r.message.print_format) {
me.frm.pos_print_format = r.message.print_format;
}
me.frm.script_manager.trigger("update_stock");
me.frm.trigger("update_stock");
if(me.frm.doc.taxes_and_charges) {
me.frm.script_manager.trigger("taxes_and_charges");
}
@ -446,35 +446,6 @@ erpnext.accounts.SalesInvoiceController = erpnext.selling.SellingController.exte
// for backward compatibility: combine new and previous states
$.extend(cur_frm.cscript, new erpnext.accounts.SalesInvoiceController({frm: cur_frm}));
// Hide Fields
// ------------
cur_frm.cscript.hide_fields = function(doc) {
var parent_fields = ['project', 'due_date', 'is_opening', 'source', 'total_advance', 'get_advances',
'advances', 'from_date', 'to_date'];
if(cint(doc.is_pos) == 1) {
hide_field(parent_fields);
} else {
for (var i in parent_fields) {
var docfield = frappe.meta.docfield_map[doc.doctype][parent_fields[i]];
if(!docfield.hidden) unhide_field(parent_fields[i]);
}
}
// India related fields
if (frappe.boot.sysdefaults.country == 'India') unhide_field(['c_form_applicable', 'c_form_no']);
else hide_field(['c_form_applicable', 'c_form_no']);
this.frm.toggle_enable("write_off_amount", !!!cint(doc.write_off_outstanding_amount_automatically));
cur_frm.refresh_fields();
}
cur_frm.cscript.update_stock = function(doc, dt, dn) {
cur_frm.cscript.hide_fields(doc, dt, dn);
this.frm.fields_dict.items.grid.toggle_reqd("item_code", doc.update_stock? true: false)
}
cur_frm.cscript['Make Delivery Note'] = function() {
frappe.model.open_mapped_doc({
method: "erpnext.accounts.doctype.sales_invoice.sales_invoice.make_delivery_note",
@ -719,6 +690,12 @@ frappe.ui.form.on('Sales Invoice', {
frm.redemption_conversion_factor = null;
},
update_stock: function(frm, dt, dn) {
frm.events.hide_fields(frm);
frm.fields_dict.items.grid.toggle_reqd("item_code", frm.doc.update_stock);
frm.trigger('reset_posting_time');
},
redeem_loyalty_points: function(frm) {
frm.events.get_loyalty_details(frm);
},
@ -742,6 +719,29 @@ frappe.ui.form.on('Sales Invoice', {
}
},
hide_fields: function(frm) {
let doc = frm.doc;
var parent_fields = ['project', 'due_date', 'is_opening', 'source', 'total_advance', 'get_advances',
'advances', 'from_date', 'to_date'];
if(cint(doc.is_pos) == 1) {
hide_field(parent_fields);
} else {
for (var i in parent_fields) {
var docfield = frappe.meta.docfield_map[doc.doctype][parent_fields[i]];
if(!docfield.hidden) unhide_field(parent_fields[i]);
}
}
// India related fields
if (frappe.boot.sysdefaults.country == 'India') unhide_field(['c_form_applicable', 'c_form_no']);
else hide_field(['c_form_applicable', 'c_form_no']);
frm.toggle_enable("write_off_amount", !!!cint(doc.write_off_outstanding_amount_automatically));
frm.refresh_fields();
},
get_loyalty_details: function(frm) {
if (frm.doc.customer && frm.doc.redeem_loyalty_points) {
frappe.call({
@ -924,7 +924,7 @@ var get_healthcare_services_to_invoice = function(frm) {
if(patient && patient!=selected_patient){
selected_patient = patient;
var method = "erpnext.healthcare.utils.get_healthcare_services_to_invoice";
var args = {patient: patient};
var args = {patient: patient, company: frm.doc.company};
var columns = (["service", "reference_name", "reference_type"]);
get_healthcare_items(frm, true, $results, $placeholder, method, args, columns);
}
@ -1068,7 +1068,11 @@ var get_drugs_to_invoice = function(frm) {
description:'Quantity will be calculated only for items which has "Nos" as UoM. You may change as required for each invoice item.',
get_query: function(doc) {
return {
filters: { patient: dialog.get_value("patient"), docstatus: 1 }
filters: {
patient: dialog.get_value("patient"),
company: frm.doc.company,
docstatus: 1
}
};
}
},

View File

@ -149,9 +149,9 @@
"edit_printing_settings",
"letter_head",
"group_same_items",
"language",
"column_break_84",
"select_print_heading",
"column_break_84",
"language",
"more_information",
"inter_company_invoice_reference",
"is_internal_customer",
@ -398,7 +398,7 @@
{
"allow_on_submit": 1,
"fieldname": "po_no",
"fieldtype": "Data",
"fieldtype": "Small Text",
"label": "Customer's Purchase Order",
"no_copy": 1,
"print_hide": 1
@ -1579,7 +1579,7 @@
"idx": 181,
"is_submittable": 1,
"links": [],
"modified": "2020-04-17 12:38:41.435728",
"modified": "2020-05-19 17:00:57.208696",
"modified_by": "Administrator",
"module": "Accounts",
"name": "Sales Invoice",

View File

@ -7,7 +7,6 @@ import frappe.defaults
from frappe.utils import cint, flt, add_months, today, date_diff, getdate, add_days, cstr, nowdate
from frappe import _, msgprint, throw
from erpnext.accounts.party import get_party_account, get_due_date
from erpnext.controllers.stock_controller import update_gl_entries_after
from frappe.model.mapper import get_mapped_doc
from erpnext.accounts.doctype.sales_invoice.pos import update_multi_mode_option
@ -282,6 +281,8 @@ class SalesInvoice(SellingController):
if "Healthcare" in active_domains:
manage_invoice_submit_cancel(self, "on_cancel")
self.ignore_linked_doctypes = ('GL Entry', 'Stock Ledger Entry')
def update_status_updater_args(self):
if cint(self.update_stock):
self.status_updater.append({
@ -717,7 +718,9 @@ class SalesInvoice(SellingController):
if d.delivery_note and frappe.db.get_value("Delivery Note", d.delivery_note, "docstatus") != 1:
throw(_("Delivery Note {0} is not submitted").format(d.delivery_note))
def make_gl_entries(self, gl_entries=None, repost_future_gle=True, from_repost=False):
def make_gl_entries(self, gl_entries=None):
from erpnext.accounts.general_ledger import make_reverse_gl_entries
auto_accounting_for_stock = erpnext.is_perpetual_inventory_enabled(self.company)
if not gl_entries:
gl_entries = self.get_gl_entries()
@ -729,23 +732,19 @@ class SalesInvoice(SellingController):
update_outstanding = "No" if (cint(self.is_pos) or self.write_off_account or
cint(self.redeem_loyalty_points)) else "Yes"
make_gl_entries(gl_entries, cancel=(self.docstatus == 2),
update_outstanding=update_outstanding, merge_entries=False, from_repost=from_repost)
if self.docstatus == 1:
make_gl_entries(gl_entries, update_outstanding=update_outstanding, merge_entries=False)
elif self.docstatus == 2:
make_reverse_gl_entries(voucher_type=self.doctype, voucher_no=self.name)
if update_outstanding == "No":
from erpnext.accounts.doctype.gl_entry.gl_entry import update_outstanding_amt
update_outstanding_amt(self.debit_to, "Customer", self.customer,
self.doctype, self.return_against if cint(self.is_return) and self.return_against else self.name)
if (repost_future_gle or self.flags.repost_future_gle) and cint(self.update_stock) \
and cint(auto_accounting_for_stock):
items, warehouses = self.get_items_and_warehouses()
update_gl_entries_after(self.posting_date, self.posting_time,
warehouses, items, company = self.company)
elif self.docstatus == 2 and cint(self.update_stock) \
and cint(auto_accounting_for_stock):
from erpnext.accounts.general_ledger import delete_gl_entries
delete_gl_entries(voucher_type=self.doctype, voucher_no=self.name)
make_reverse_gl_entries(voucher_type=self.doctype, voucher_no=self.name)
def get_gl_entries(self, warehouse_account=None):
from erpnext.accounts.general_ledger import merge_similar_entries
@ -792,7 +791,7 @@ class SalesInvoice(SellingController):
"against_voucher": self.return_against if cint(self.is_return) and self.return_against else self.name,
"against_voucher_type": self.doctype,
"cost_center": self.cost_center
}, self.party_account_currency)
}, self.party_account_currency, item=self)
)
def make_tax_gl_entries(self, gl_entries):
@ -809,7 +808,7 @@ class SalesInvoice(SellingController):
tax.precision("base_tax_amount_after_discount_amount")) if account_currency==self.company_currency else
flt(tax.tax_amount_after_discount_amount, tax.precision("tax_amount_after_discount_amount"))),
"cost_center": tax.cost_center
}, account_currency)
}, account_currency, item=tax)
)
def make_item_gl_entries(self, gl_entries):
@ -829,7 +828,7 @@ class SalesInvoice(SellingController):
for gle in fixed_asset_gl_entries:
gle["against"] = self.customer
gl_entries.append(self.get_gl_dict(gle))
gl_entries.append(self.get_gl_dict(gle, item=item))
asset.db_set("disposal_date", self.posting_date)
asset.set_status("Sold" if self.docstatus==1 else None)
@ -867,7 +866,7 @@ class SalesInvoice(SellingController):
"against_voucher": self.return_against if cint(self.is_return) else self.name,
"against_voucher_type": self.doctype,
"cost_center": self.cost_center
})
}, item=self)
)
gl_entries.append(
self.get_gl_dict({
@ -876,7 +875,7 @@ class SalesInvoice(SellingController):
"against": self.customer,
"debit": self.loyalty_amount,
"remark": "Loyalty Points redeemed by the customer"
})
}, item=self)
)
def make_pos_gl_entries(self, gl_entries):
@ -897,7 +896,7 @@ class SalesInvoice(SellingController):
"against_voucher": self.return_against if cint(self.is_return) and self.return_against else self.name,
"against_voucher_type": self.doctype,
"cost_center": self.cost_center
}, self.party_account_currency)
}, self.party_account_currency, item=self)
)
payment_mode_account_currency = get_account_currency(payment_mode.account)
@ -910,7 +909,7 @@ class SalesInvoice(SellingController):
if payment_mode_account_currency==self.company_currency \
else payment_mode.amount,
"cost_center": self.cost_center
}, payment_mode_account_currency)
}, payment_mode_account_currency, item=self)
)
def make_gle_for_change_amount(self, gl_entries):
@ -928,7 +927,7 @@ class SalesInvoice(SellingController):
"against_voucher": self.return_against if cint(self.is_return) and self.return_against else self.name,
"against_voucher_type": self.doctype,
"cost_center": self.cost_center
}, self.party_account_currency)
}, self.party_account_currency, item=self)
)
gl_entries.append(
@ -937,7 +936,7 @@ class SalesInvoice(SellingController):
"against": self.customer,
"credit": self.base_change_amount,
"cost_center": self.cost_center
})
}, item=self)
)
else:
frappe.throw(_("Select change amount account"), title="Mandatory Field")
@ -961,7 +960,7 @@ class SalesInvoice(SellingController):
"against_voucher": self.return_against if cint(self.is_return) else self.name,
"against_voucher_type": self.doctype,
"cost_center": self.cost_center
}, self.party_account_currency)
}, self.party_account_currency, item=self)
)
gl_entries.append(
self.get_gl_dict({
@ -972,7 +971,7 @@ class SalesInvoice(SellingController):
self.precision("base_write_off_amount")) if write_off_account_currency==self.company_currency
else flt(self.write_off_amount, self.precision("write_off_amount"))),
"cost_center": self.cost_center or self.write_off_cost_center or default_cost_center
}, write_off_account_currency)
}, write_off_account_currency, item=self)
)
def make_gle_for_rounding_adjustment(self, gl_entries):
@ -989,8 +988,7 @@ class SalesInvoice(SellingController):
"credit": flt(self.base_rounding_adjustment,
self.precision("base_rounding_adjustment")),
"cost_center": self.cost_center or round_off_cost_center,
}
))
}, item=self))
def update_billing_status_in_dn(self, update_modified=True):
updated_delivery_notes = []

View File

@ -5,7 +5,7 @@ from __future__ import unicode_literals
import frappe
import unittest, copy, time
from frappe.utils import nowdate, flt, getdate, cint, add_days
from frappe.utils import nowdate, flt, getdate, cint, add_days, add_months
from frappe.model.dynamic_links import get_dynamic_link_map
from erpnext.stock.doctype.stock_entry.test_stock_entry import make_stock_entry, get_qty_after_transaction
from erpnext.accounts.doctype.purchase_invoice.test_purchase_invoice import unlink_payment_on_cancel_of_invoice
@ -364,7 +364,7 @@ class TestSalesInvoice(unittest.TestCase):
gle = frappe.db.sql("""select * from `tabGL Entry`
where voucher_type='Sales Invoice' and voucher_no=%s""", si.name)
self.assertFalse(gle)
self.assertTrue(gle)
def test_tax_calculation_with_multiple_items(self):
si = create_sales_invoice(qty=84, rate=4.6, do_not_save=True)
@ -678,14 +678,15 @@ class TestSalesInvoice(unittest.TestCase):
gle = frappe.db.sql("""select * from `tabGL Entry`
where voucher_type='Sales Invoice' and voucher_no=%s""", si.name)
self.assertFalse(gle)
self.assertTrue(gle)
def test_pos_gl_entry_with_perpetual_inventory(self):
make_pos_profile()
pr = make_purchase_receipt(company= "_Test Company with perpetual inventory",supplier_warehouse= "Work In Progress - TCP1", item_code= "_Test FG Item",warehouse= "Stores - TCP1",cost_center= "Main - TCP1")
pr = make_purchase_receipt(company= "_Test Company with perpetual inventory", item_code= "_Test FG Item",warehouse= "Stores - TCP1",cost_center= "Main - TCP1")
pos = create_sales_invoice(company= "_Test Company with perpetual inventory", debit_to="Debtors - TCP1", item_code= "_Test FG Item", warehouse="Stores - TCP1", income_account = "Sales - TCP1", expense_account = "Cost of Goods Sold - TCP1", cost_center = "Main - TCP1", do_not_save=True)
pos = create_sales_invoice(company= "_Test Company with perpetual inventory", debit_to="Debtors - TCP1", item_code= "_Test FG Item", warehouse="Stores - TCP1",
income_account = "Sales - TCP1", expense_account = "Cost of Goods Sold - TCP1", cost_center = "Main - TCP1", do_not_save=True)
pos.is_pos = 1
pos.update_stock = 1
@ -766,9 +767,13 @@ class TestSalesInvoice(unittest.TestCase):
def test_pos_change_amount(self):
make_pos_profile()
pr = make_purchase_receipt(company= "_Test Company with perpetual inventory",supplier_warehouse= "Work In Progress - TCP1", item_code= "_Test FG Item",warehouse= "Stores - TCP1",cost_center= "Main - TCP1")
pr = make_purchase_receipt(company= "_Test Company with perpetual inventory",
item_code= "_Test FG Item",warehouse= "Stores - TCP1", cost_center= "Main - TCP1")
pos = create_sales_invoice(company= "_Test Company with perpetual inventory", debit_to="Debtors - TCP1", item_code= "_Test FG Item", warehouse="Stores - TCP1", income_account = "Sales - TCP1", expense_account = "Cost of Goods Sold - TCP1", cost_center = "Main - TCP1", do_not_save=True)
pos = create_sales_invoice(company= "_Test Company with perpetual inventory",
debit_to="Debtors - TCP1", item_code= "_Test FG Item", warehouse="Stores - TCP1",
income_account = "Sales - TCP1", expense_account = "Cost of Goods Sold - TCP1",
cost_center = "Main - TCP1", do_not_save=True)
pos.is_pos = 1
pos.update_stock = 1
@ -787,8 +792,15 @@ class TestSalesInvoice(unittest.TestCase):
from erpnext.accounts.doctype.sales_invoice.pos import make_invoice
pos_profile = make_pos_profile()
pr = make_purchase_receipt(company= "_Test Company with perpetual inventory",supplier_warehouse= "Work In Progress - TCP1", item_code= "_Test FG Item",warehouse= "Stores - TCP1",cost_center= "Main - TCP1")
pos = create_sales_invoice(company= "_Test Company with perpetual inventory", debit_to="Debtors - TCP1", item_code= "_Test FG Item", warehouse="Stores - TCP1", income_account = "Sales - TCP1", expense_account = "Cost of Goods Sold - TCP1", cost_center = "Main - TCP1", do_not_save=True)
pr = make_purchase_receipt(company= "_Test Company with perpetual inventory",
item_code= "_Test FG Item",
warehouse= "Stores - TCP1", cost_center= "Main - TCP1")
pos = create_sales_invoice(company= "_Test Company with perpetual inventory",
debit_to="Debtors - TCP1", item_code= "_Test FG Item", warehouse="Stores - TCP1",
income_account = "Sales - TCP1", expense_account = "Cost of Goods Sold - TCP1",
cost_center = "Main - TCP1", do_not_save=True)
pos.is_pos = 1
pos.update_stock = 1
@ -891,11 +903,9 @@ class TestSalesInvoice(unittest.TestCase):
gle = frappe.db.sql("""select * from `tabGL Entry`
where voucher_type='Sales Invoice' and voucher_no=%s""", si.name)
self.assertFalse(gle)
self.assertTrue(gle)
frappe.db.sql("delete from `tabPOS Profile`")
si.delete()
def test_pos_si_without_payment(self):
set_perpetual_inventory()
@ -1012,9 +1022,6 @@ class TestSalesInvoice(unittest.TestCase):
si.cancel()
self.assertTrue(not frappe.db.sql("""select name from `tabJournal Entry Account`
where reference_name=%s""", si.name))
def test_serialized(self):
from erpnext.stock.doctype.stock_entry.test_stock_entry import make_serialized_item
from erpnext.stock.doctype.serial_no.serial_no import get_serial_nos
@ -1230,7 +1237,7 @@ class TestSalesInvoice(unittest.TestCase):
gle = frappe.db.sql("""select name from `tabGL Entry`
where voucher_type='Sales Invoice' and voucher_no=%s""", si.name)
self.assertFalse(gle)
self.assertTrue(gle)
def test_invalid_currency(self):
# Customer currency = USD
@ -1714,37 +1721,76 @@ class TestSalesInvoice(unittest.TestCase):
si.submit()
from erpnext.accounts.deferred_revenue import convert_deferred_revenue_to_income
convert_deferred_revenue_to_income(start_date="2019-01-01", end_date="2019-01-31")
pda1 = 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"
))
pda1.insert()
pda1.submit()
expected_gle = [
[deferred_account, 33.85, 0.0, "2019-01-31"],
["Sales - _TC", 0.0, 33.85, "2019-01-31"]
]
self.check_gl_entries(si.name, expected_gle, "2019-01-10")
convert_deferred_revenue_to_income(start_date="2019-01-01", end_date="2019-03-31")
expected_gle = [
["Sales - _TC", 0.0, 33.85, "2019-01-31"],
[deferred_account, 43.08, 0.0, "2019-02-28"],
["Sales - _TC", 0.0, 43.08, "2019-02-28"],
[deferred_account, 23.07, 0.0, "2019-03-15"],
["Sales - _TC", 0.0, 23.07, "2019-03-15"]
]
self.check_gl_entries(si.name, expected_gle, "2019-01-31")
check_gl_entries(self, si.name, expected_gle, "2019-01-30")
def check_gl_entries(self, voucher_no, expected_gle, posting_date):
gl_entries = frappe.db.sql("""select account, debit, credit, posting_date
from `tabGL Entry`
where voucher_type='Sales Invoice' and voucher_no=%s and posting_date > %s
order by posting_date asc, account asc""", (voucher_no, posting_date), as_dict=1)
def test_deferred_error_email(self):
deferred_account = create_account(account_name="Deferred Revenue",
parent_account="Current Liabilities - _TC", company="_Test Company")
for i, gle in enumerate(gl_entries):
self.assertEqual(expected_gle[i][0], gle.account)
self.assertEqual(expected_gle[i][1], gle.debit)
self.assertEqual(expected_gle[i][2], gle.credit)
self.assertEqual(getdate(expected_gle[i][3]), gle.posting_date)
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):
@ -1892,7 +1938,7 @@ class TestSalesInvoice(unittest.TestCase):
si.submit()
data = get_ewb_data("Sales Invoice", si.name)
data = get_ewb_data("Sales Invoice", [si.name])
self.assertEqual(data['version'], '1.0.1118')
self.assertEqual(data['billLists'][0]['fromGstin'], '27AAECE4835E1ZR')
@ -1905,6 +1951,18 @@ class TestSalesInvoice(unittest.TestCase):
self.assertEqual(data['billLists'][0]['vehicleNo'], 'KA12KA1234')
self.assertEqual(data['billLists'][0]['itemList'][0]['taxableAmount'], 60000)
def check_gl_entries(doc, voucher_no, expected_gle, posting_date):
gl_entries = frappe.db.sql("""select account, debit, credit, posting_date
from `tabGL Entry`
where voucher_type='Sales Invoice' and voucher_no=%s and posting_date > %s
order by posting_date asc, account asc""", (voucher_no, posting_date), as_dict=1)
for i, gle in enumerate(gl_entries):
doc.assertEqual(expected_gle[i][0], gle.account)
doc.assertEqual(expected_gle[i][1], gle.debit)
doc.assertEqual(expected_gle[i][2], gle.credit)
doc.assertEqual(getdate(expected_gle[i][3]), gle.posting_date)
def test_item_tax_validity(self):
item = frappe.get_doc("Item", "_Test Item 2")

View File

@ -168,18 +168,20 @@ class ShareTransfer(Document):
return 'Outside'
def folio_no_validation(self):
shareholders = ['from_shareholder', 'to_shareholder']
shareholders = [shareholder for shareholder in shareholders if self.get(shareholder) is not '']
for shareholder in shareholders:
doc = self.get_shareholder_doc(self.get(shareholder))
shareholder_fields = ['from_shareholder', 'to_shareholder']
for shareholder_field in shareholder_fields:
shareholder_name = self.get(shareholder_field)
if not shareholder_name:
continue
doc = self.get_shareholder_doc(shareholder_name)
if doc.company != self.company:
frappe.throw(_('The shareholder does not belong to this company'))
if not doc.folio_no:
doc.folio_no = self.from_folio_no \
if (shareholder == 'from_shareholder') else self.to_folio_no
if (shareholder_field == 'from_shareholder') else self.to_folio_no
doc.save()
else:
if doc.folio_no and doc.folio_no != (self.from_folio_no if (shareholder == 'from_shareholder') else self.to_folio_no):
if doc.folio_no and doc.folio_no != (self.from_folio_no if (shareholder_field == 'from_shareholder') else self.to_folio_no):
frappe.throw(_('The folio numbers are not matching'))
def autoname_folio(self, shareholder, is_company=False):

View File

@ -58,7 +58,7 @@ def get_tax_withholding_details(tax_withholding_category, fiscal_year, company):
"rate": tax_rate_detail.tax_withholding_rate,
"threshold": tax_rate_detail.single_threshold,
"cumulative_threshold": tax_rate_detail.cumulative_threshold,
"description": tax_withholding.category_name
"description": tax_withholding.category_name if tax_withholding.category_name else tax_withholding_category
})
def get_tax_withholding_rates(tax_withholding, fiscal_year):

View File

@ -3,7 +3,7 @@
from __future__ import unicode_literals
import frappe, erpnext
from frappe.utils import flt, cstr, cint, comma_and
from frappe.utils import flt, cstr, cint, comma_and, today, getdate, formatdate, now
from frappe import _
from erpnext.accounts.utils import get_stock_and_account_balance
from frappe.model.meta import get_field_precision
@ -15,17 +15,17 @@ class ClosedAccountingPeriod(frappe.ValidationError): pass
class StockAccountInvalidTransaction(frappe.ValidationError): pass
class StockValueAndAccountBalanceOutOfSync(frappe.ValidationError): pass
def make_gl_entries(gl_map, cancel=False, adv_adj=False, merge_entries=True, update_outstanding='Yes', from_repost=False):
def make_gl_entries(gl_map, cancel=False, adv_adj=False, merge_entries=True, update_outstanding='Yes'):
if gl_map:
if not cancel:
validate_accounting_period(gl_map)
gl_map = process_gl_map(gl_map, merge_entries)
if gl_map and len(gl_map) > 1:
save_entries(gl_map, adv_adj, update_outstanding, from_repost)
save_entries(gl_map, adv_adj, update_outstanding)
else:
frappe.throw(_("Incorrect number of General Ledger Entries found. You might have selected a wrong Account in the transaction."))
else:
delete_gl_entries(gl_map, adv_adj=adv_adj, update_outstanding=update_outstanding)
make_reverse_gl_entries(gl_map, adv_adj=adv_adj, update_outstanding=update_outstanding)
def validate_accounting_period(gl_map):
accounting_periods = frappe.db.sql(""" SELECT
@ -119,33 +119,36 @@ def check_if_in_list(gle, gl_map, dimensions=None):
if same_head:
return e
def save_entries(gl_map, adv_adj, update_outstanding, from_repost=False):
if not from_repost:
validate_cwip_accounts(gl_map)
def save_entries(gl_map, adv_adj, update_outstanding):
validate_cwip_accounts(gl_map)
round_off_debit_credit(gl_map)
if gl_map:
check_freezing_date(gl_map[0]["posting_date"], adv_adj)
for entry in gl_map:
make_entry(entry, adv_adj, update_outstanding, from_repost)
make_entry(entry, adv_adj, update_outstanding)
# check against budget
if not from_repost:
validate_expense_against_budget(entry)
validate_expense_against_budget(entry)
if not from_repost:
validate_account_for_perpetual_inventory(gl_map)
validate_account_for_perpetual_inventory(gl_map)
def make_entry(args, adv_adj, update_outstanding, from_repost=False):
def make_entry(args, adv_adj, update_outstanding):
gle = frappe.new_doc("GL Entry")
gle.update(args)
gle.flags.ignore_permissions = 1
gle.flags.from_repost = from_repost
gle.validate()
gle.db_insert()
gle.run_method("on_update_with_args", adv_adj, update_outstanding, from_repost)
gle.run_method("on_update_with_args", adv_adj, update_outstanding)
gle.flags.ignore_validate = True
gle.submit()
# check against budget
validate_expense_against_budget(args)
def validate_account_for_perpetual_inventory(gl_map):
if cint(erpnext.is_perpetual_inventory_enabled(gl_map[0].company)):
account_list = [gl_entries.account for gl_entries in gl_map]
@ -169,33 +172,33 @@ def validate_account_for_perpetual_inventory(gl_map):
.format(account), StockAccountInvalidTransaction)
# This has been comment for a temporary, will add this code again on release of immutable ledger
# elif account_bal != stock_bal:
# precision = get_field_precision(frappe.get_meta("GL Entry").get_field("debit"),
# currency=frappe.get_cached_value('Company', gl_map[0].company, "default_currency"))
elif account_bal != stock_bal:
precision = get_field_precision(frappe.get_meta("GL Entry").get_field("debit"),
currency=frappe.get_cached_value('Company', gl_map[0].company, "default_currency"))
# diff = flt(stock_bal - account_bal, precision)
# error_reason = _("Stock Value ({0}) and Account Balance ({1}) are out of sync for account {2} and it's linked warehouses.").format(
# stock_bal, account_bal, frappe.bold(account))
# error_resolution = _("Please create adjustment Journal Entry for amount {0} ").format(frappe.bold(diff))
# stock_adjustment_account = frappe.db.get_value("Company",gl_map[0].company,"stock_adjustment_account")
diff = flt(stock_bal - account_bal, precision)
error_reason = _("Stock Value ({0}) and Account Balance ({1}) are out of sync for account {2} and it's linked warehouses.").format(
stock_bal, account_bal, frappe.bold(account))
error_resolution = _("Please create adjustment Journal Entry for amount {0} ").format(frappe.bold(diff))
stock_adjustment_account = frappe.db.get_value("Company",gl_map[0].company,"stock_adjustment_account")
# db_or_cr_warehouse_account =('credit_in_account_currency' if diff < 0 else 'debit_in_account_currency')
# db_or_cr_stock_adjustment_account = ('debit_in_account_currency' if diff < 0 else 'credit_in_account_currency')
db_or_cr_warehouse_account =('credit_in_account_currency' if diff < 0 else 'debit_in_account_currency')
db_or_cr_stock_adjustment_account = ('debit_in_account_currency' if diff < 0 else 'credit_in_account_currency')
# journal_entry_args = {
# 'accounts':[
# {'account': account, db_or_cr_warehouse_account : abs(diff)},
# {'account': stock_adjustment_account, db_or_cr_stock_adjustment_account : abs(diff) }]
# }
journal_entry_args = {
'accounts':[
{'account': account, db_or_cr_warehouse_account : abs(diff)},
{'account': stock_adjustment_account, db_or_cr_stock_adjustment_account : abs(diff) }]
}
# frappe.msgprint(msg="""{0}<br></br>{1}<br></br>""".format(error_reason, error_resolution),
# raise_exception=StockValueAndAccountBalanceOutOfSync,
# title=_('Values Out Of Sync'),
# primary_action={
# 'label': _('Make Journal Entry'),
# 'client_action': 'erpnext.route_to_adjustment_jv',
# 'args': journal_entry_args
# })
frappe.msgprint(msg="""{0}<br></br>{1}<br></br>""".format(error_reason, error_resolution),
raise_exception=StockValueAndAccountBalanceOutOfSync,
title=_('Values Out Of Sync'),
primary_action={
'label': _('Make Journal Entry'),
'client_action': 'erpnext.route_to_adjustment_jv',
'args': journal_entry_args
})
def validate_cwip_accounts(gl_map):
cwip_enabled = any([cint(ac.enable_cwip_accounting) for ac in frappe.db.get_all("Asset Category","enable_cwip_accounting")])
@ -282,31 +285,65 @@ def get_round_off_account_and_cost_center(company):
return round_off_account, round_off_cost_center
def delete_gl_entries(gl_entries=None, voucher_type=None, voucher_no=None,
adv_adj=False, update_outstanding="Yes"):
from erpnext.accounts.doctype.gl_entry.gl_entry import validate_balance_type, \
check_freezing_date, update_outstanding_amt, validate_frozen_account
def make_reverse_gl_entries(gl_entries=None, voucher_type=None, voucher_no=None,
adv_adj=False, update_outstanding="Yes"):
"""
Get original gl entries of the voucher
and make reverse gl entries by swapping debit and credit
"""
if not gl_entries:
gl_entries = frappe.db.sql("""
select account, posting_date, party_type, party, cost_center, fiscal_year,voucher_type,
voucher_no, against_voucher_type, against_voucher, cost_center, company
from `tabGL Entry`
where voucher_type=%s and voucher_no=%s""", (voucher_type, voucher_no), as_dict=True)
gl_entries = frappe.get_all("GL Entry",
fields = ["*"],
filters = {
"voucher_type": voucher_type,
"voucher_no": voucher_no,
"is_cancelled": 0
})
if gl_entries:
set_as_cancel(gl_entries[0]['voucher_type'], gl_entries[0]['voucher_no'])
check_freezing_date(gl_entries[0]["posting_date"], adv_adj)
frappe.db.sql("""delete from `tabGL Entry` where voucher_type=%s and voucher_no=%s""",
(voucher_type or gl_entries[0]["voucher_type"], voucher_no or gl_entries[0]["voucher_no"]))
for entry in gl_entries:
entry['name'] = None
debit = entry.get('debit', 0)
credit = entry.get('credit', 0)
for entry in gl_entries:
validate_frozen_account(entry["account"], adv_adj)
validate_balance_type(entry["account"], adv_adj)
if not adv_adj:
validate_expense_against_budget(entry)
debit_in_account_currency = entry.get('debit_in_account_currency', 0)
credit_in_account_currency = entry.get('credit_in_account_currency', 0)
if entry.get("against_voucher") and update_outstanding == 'Yes' and not adv_adj:
update_outstanding_amt(entry["account"], entry.get("party_type"), entry.get("party"), entry.get("against_voucher_type"),
entry.get("against_voucher"), on_cancel=True)
entry['debit'] = credit
entry['credit'] = debit
entry['debit_in_account_currency'] = credit_in_account_currency
entry['credit_in_account_currency'] = debit_in_account_currency
entry['remarks'] = "On cancellation of " + entry['voucher_no']
entry['is_cancelled'] = 1
entry['posting_date'] = today()
if entry['debit'] or entry['credit']:
make_entry(entry, adv_adj, "Yes")
def check_freezing_date(posting_date, adv_adj=False):
"""
Nobody can do GL Entries where posting date is before freezing date
except authorized person
"""
if not adv_adj:
acc_frozen_upto = frappe.db.get_value('Accounts Settings', None, 'acc_frozen_upto')
if acc_frozen_upto:
frozen_accounts_modifier = frappe.db.get_value( 'Accounts Settings', None,'frozen_accounts_modifier')
if getdate(posting_date) <= getdate(acc_frozen_upto) \
and not frozen_accounts_modifier in frappe.get_roles():
frappe.throw(_("You are not authorized to add or update entries before {0}").format(formatdate(acc_frozen_upto)))
def set_as_cancel(voucher_type, voucher_no):
"""
Set is_cancelled=1 in all original gl entries for the voucher
"""
frappe.db.sql("""update `tabGL Entry` set is_cancelled = 1,
modified=%s, modified_by=%s
where voucher_type=%s and voucher_no=%s and is_cancelled = 0""",
(now(), frappe.session.user, voucher_type, voucher_no))

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

@ -162,7 +162,7 @@ def get_default_price_list(party):
def set_price_list(party_details, party, party_type, given_price_list, pos=None):
# price list
price_list = get_permitted_documents('Price List')
# if there is only one permitted document based on user permissions, set it
if price_list and len(price_list) == 1:
price_list = price_list[0]
@ -465,23 +465,25 @@ def get_timeline_data(doctype, name):
from frappe.desk.form.load import get_communication_data
out = {}
fields = 'date(creation), count(name)'
fields = 'creation, count(*)'
after = add_years(None, -1).strftime('%Y-%m-%d')
group_by='group by date(creation)'
group_by='group by Date(creation)'
data = get_communication_data(doctype, name, after=after, group_by='group by date(creation)',
fields='date(C.creation) as creation, count(C.name)',as_dict=False)
data = get_communication_data(doctype, name, after=after, group_by='group by creation',
fields='C.creation as creation, count(C.name)',as_dict=False)
# fetch and append data from Activity Log
data += frappe.db.sql("""select {fields}
from `tabActivity Log`
where (reference_doctype="{doctype}" and reference_name="{name}")
or (timeline_doctype in ("{doctype}") and timeline_name="{name}")
or (reference_doctype in ("Quotation", "Opportunity") and timeline_name="{name}")
where (reference_doctype=%(doctype)s and reference_name=%(name)s)
or (timeline_doctype in (%(doctype)s) and timeline_name=%(name)s)
or (reference_doctype in ("Quotation", "Opportunity") and timeline_name=%(name)s)
and status!='Success' and creation > {after}
{group_by} order by creation desc
""".format(doctype=frappe.db.escape(doctype), name=frappe.db.escape(name), fields=fields,
group_by=group_by, after=after), as_dict=False)
""".format(fields=fields, group_by=group_by, after=after), {
"doctype": doctype,
"name": name
}, as_dict=False)
timeline_items = dict(data)
@ -600,10 +602,12 @@ def get_party_shipping_address(doctype, name):
else:
return ''
def get_partywise_advanced_payment_amount(party_type, posting_date = None):
def get_partywise_advanced_payment_amount(party_type, posting_date = None, company=None):
cond = "1=1"
if posting_date:
cond = "posting_date <= '{0}'".format(posting_date)
if company:
cond += "and company = '{0}'".format(company)
data = frappe.db.sql(""" SELECT party, sum({0}) as amount
FROM `tabGL Entry`

View File

@ -534,7 +534,7 @@ class ReceivablePayableReport(object):
def get_ageing_data(self, entry_date, row):
# [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):
return
@ -546,7 +546,7 @@ class ReceivablePayableReport(object):
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]):
if row.age <= days:
if cint(row.age) <= cint(days):
index = i
break

View File

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

View File

@ -2,16 +2,19 @@
# License: GNU General Public License v3. See license.txt
from __future__ import unicode_literals
import datetime
from six import iteritems
import frappe
from frappe import _
from frappe.utils import flt
from frappe.utils import formatdate
from frappe.utils import flt, formatdate
from erpnext.controllers.trends import get_period_date_ranges, get_period_month_ranges
from six import iteritems
from pprint import pprint
def execute(filters=None):
if not filters: filters = {}
if not filters:
filters = {}
columns = get_columns(filters)
if filters.get("budget_against_filter"):
@ -43,20 +46,37 @@ def execute(filters=None):
period_data[0] += last_total
if(filters.get("show_cumulative")):
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" :
if filters["period"] != "Yearly":
row += totals
data.append(row)
return columns, data
chart = get_chart_data(filters, columns, data)
return columns, data, None, chart
def get_columns(filters):
columns = [_(filters.get("budget_against")) + ":Link/%s:150"%(filters.get("budget_against")), _("Account") + ":Link/Account:150"]
columns = [
{
'label': _(filters.get("budget_against")),
'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
@ -65,84 +85,195 @@ def get_columns(filters):
for year in fiscal_year:
for from_date, to_date in get_period_date_ranges(filters["period"], year[0]):
if filters["period"] == "Yearly":
labels = [_("Budget") + " " + str(year[0]), _("Actual ") + " " + str(year[0]), _("Variance ") + " " + str(year[0])]
labels = [
_("Budget") + " " + str(year[0]),
_("Actual ") + " " + str(year[0]),
_("Variance ") + " " + str(year[0])
]
for label in labels:
columns.append(label+":Float:150")
columns.append({
'label': label,
'fieldtype': 'Float',
'fieldname': frappe.scrub(label),
'width': 150
})
else:
for label in [_("Budget") + " (%s)" + " " + str(year[0]), _("Actual") + " (%s)" + " " + str(year[0]), _("Variance") + " (%s)" + " " + str(year[0])]:
for label in [
_("Budget") + " (%s)" + " " + str(year[0]),
_("Actual") + " (%s)" + " " + str(year[0]),
_("Variance") + " (%s)" + " " + str(year[0])
]:
if group_months:
label = label % (formatdate(from_date, format_string="MMM") + "-" + formatdate(to_date, format_string="MMM"))
label = label % (
formatdate(from_date, format_string="MMM")
+ "-"
+ formatdate(to_date, format_string="MMM")
)
else:
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" :
return columns + [_("Total Budget") + ":Float:150", _("Total Actual") + ":Float:150",
_("Total Variance") + ":Float:150"]
if filters["period"] != "Yearly":
for label in [_("Total Budget"), _("Total Actual"), _("Total Variance")]:
columns.append({
'label': label,
'fieldtype': 'Float',
'fieldname': frappe.scrub(label),
'width': 150
})
return columns
else:
return columns
def get_cost_centers(filters):
cond = "and 1=1"
order_by = ""
if filters.get("budget_against") == "Cost Center":
cond = "order by lft"
order_by = "order by lft"
if filters.get("budget_against") in ["Cost Center", "Project"]:
return frappe.db.sql_list("""select name from `tab{tab}` where company=%s
{cond}""".format(tab=filters.get("budget_against"), cond=cond), filters.get("company"))
return frappe.db.sql_list(
"""
select
name
from
`tab{tab}`
where
company = %s
{order_by}
""".format(tab=filters.get("budget_against"), order_by=order_by),
filters.get("company"))
else:
return frappe.db.sql_list("""select name from `tab{tab}`""".format(tab=filters.get("budget_against"))) #nosec
return frappe.db.sql_list(
"""
select
name
from
`tab{tab}`
""".format(tab=filters.get("budget_against"))) # nosec
#Get dimension & target details
# Get dimension & target details
def get_dimension_target_details(filters):
budget_against = frappe.scrub(filters.get("budget_against"))
cond = ""
if filters.get("budget_against_filter"):
cond += " and b.{budget_against} in (%s)".format(budget_against = \
frappe.scrub(filters.get('budget_against'))) % ', '.join(['%s']* len(filters.get('budget_against_filter')))
cond += """ and b.{budget_against} in (%s)""".format(
budget_against=budget_against) % ", ".join(["%s"] * len(filters.get("budget_against_filter")))
return frappe.db.sql("""
select b.{budget_against} as budget_against, b.monthly_distribution, ba.account, ba.budget_amount,b.fiscal_year
from `tabBudget` b, `tabBudget Account` ba
where b.name=ba.parent and b.docstatus = 1 and b.fiscal_year between %s and %s
and b.budget_against = %s and b.company=%s {cond} order by b.fiscal_year
""".format(budget_against=filters.get("budget_against").replace(" ", "_").lower(), cond=cond),
tuple([filters.from_fiscal_year,filters.to_fiscal_year,filters.budget_against, filters.company] + filters.get('budget_against_filter')),
as_dict=True)
return frappe.db.sql(
"""
select
b.{budget_against} as budget_against,
b.monthly_distribution,
ba.account,
ba.budget_amount,
b.fiscal_year
from
`tabBudget` b,
`tabBudget Account` ba
where
b.name = ba.parent
and b.docstatus = 1
and b.fiscal_year between %s and %s
and b.budget_against = %s
and b.company = %s
{cond}
order by
b.fiscal_year
""".format(
budget_against=budget_against,
cond=cond,
),
tuple(
[
filters.from_fiscal_year,
filters.to_fiscal_year,
filters.budget_against,
filters.company,
]
+ (filters.get("budget_against_filter") or [])
), as_dict=True)
#Get target distribution details of accounts of cost center
# Get target distribution details of accounts of cost center
def get_target_distribution_details(filters):
target_details = {}
for d in frappe.db.sql("""select md.name, mdp.month, mdp.percentage_allocation
from `tabMonthly Distribution Percentage` mdp, `tabMonthly Distribution` md
where mdp.parent=md.name and md.fiscal_year between %s and %s order by md.fiscal_year""",(filters.from_fiscal_year, filters.to_fiscal_year), as_dict=1):
target_details.setdefault(d.name, {}).setdefault(d.month, flt(d.percentage_allocation))
for d in frappe.db.sql(
"""
select
md.name,
mdp.month,
mdp.percentage_allocation
from
`tabMonthly Distribution Percentage` mdp,
`tabMonthly Distribution` md
where
mdp.parent = md.name
and md.fiscal_year between %s and %s
order by
md.fiscal_year
""",
(filters.from_fiscal_year, filters.to_fiscal_year), as_dict=1):
target_details.setdefault(d.name, {}).setdefault(
d.month, flt(d.percentage_allocation)
)
return target_details
#Get actual details from gl entry
# Get actual details from gl entry
def get_actual_details(name, filters):
cond = "1=1"
budget_against=filters.get("budget_against").replace(" ", "_").lower()
budget_against = frappe.scrub(filters.get("budget_against"))
cond = ""
if filters.get("budget_against") == "Cost Center":
cc_lft, cc_rgt = frappe.db.get_value("Cost Center", name, ["lft", "rgt"])
cond = "lft>='{lft}' and rgt<='{rgt}'".format(lft = cc_lft, rgt=cc_rgt)
cond = """
and lft >= "{lft}"
and rgt <= "{rgt}"
""".format(lft=cc_lft, rgt=cc_rgt)
ac_details = frappe.db.sql("""select gl.account, gl.debit, gl.credit,gl.fiscal_year,
MONTHNAME(gl.posting_date) as month_name, b.{budget_against} as budget_against
from `tabGL Entry` gl, `tabBudget Account` ba, `tabBudget` b
where
b.name = ba.parent
and b.docstatus = 1
and ba.account=gl.account
and b.{budget_against} = gl.{budget_against}
and gl.fiscal_year between %s and %s
and b.{budget_against}=%s
and exists(select name from `tab{tab}` where name=gl.{budget_against} and {cond}) group by gl.name order by gl.fiscal_year
""".format(tab = filters.budget_against, budget_against = budget_against, cond = cond,from_year=filters.from_fiscal_year,to_year=filters.to_fiscal_year),
(filters.from_fiscal_year, filters.to_fiscal_year, name), as_dict=1)
ac_details = frappe.db.sql(
"""
select
gl.account,
gl.debit,
gl.credit,
gl.fiscal_year,
MONTHNAME(gl.posting_date) as month_name,
b.{budget_against} as budget_against
from
`tabGL Entry` gl,
`tabBudget Account` ba,
`tabBudget` b
where
b.name = ba.parent
and b.docstatus = 1
and ba.account=gl.account
and b.{budget_against} = gl.{budget_against}
and gl.fiscal_year between %s and %s
and b.{budget_against} = %s
and exists(
select
name
from
`tab{tab}`
where
name = gl.{budget_against}
{cond}
)
group by
gl.name
order by gl.fiscal_year
""".format(tab=filters.budget_against, budget_against=budget_against, cond=cond),
(filters.from_fiscal_year, filters.to_fiscal_year, name), as_dict=1)
cc_actual_details = {}
for d in ac_details:
@ -151,7 +282,6 @@ def get_actual_details(name, filters):
return cc_actual_details
def get_dimension_account_month_map(filters):
import datetime
dimension_target_details = get_dimension_target_details(filters)
tdd = get_target_distribution_details(filters)
@ -161,28 +291,89 @@ def get_dimension_account_month_map(filters):
actual_details = get_actual_details(ccd.budget_against, filters)
for month_id in range(1, 13):
month = datetime.date(2013, month_id, 1).strftime('%B')
cam_map.setdefault(ccd.budget_against, {}).setdefault(ccd.account, {}).setdefault(ccd.fiscal_year,{})\
.setdefault(month, frappe._dict({
"target": 0.0, "actual": 0.0
}))
month = datetime.date(2013, month_id, 1).strftime("%B")
cam_map.setdefault(ccd.budget_against, {}).setdefault(
ccd.account, {}
).setdefault(ccd.fiscal_year, {}).setdefault(
month, frappe._dict({"target": 0.0, "actual": 0.0})
)
tav_dict = cam_map[ccd.budget_against][ccd.account][ccd.fiscal_year][month]
month_percentage = tdd.get(ccd.monthly_distribution, {}).get(month, 0) \
if ccd.monthly_distribution else 100.0/12
month_percentage = (
tdd.get(ccd.monthly_distribution, {}).get(month, 0)
if ccd.monthly_distribution
else 100.0 / 12
)
tav_dict.target = flt(ccd.budget_amount) * month_percentage / 100
for ad in actual_details.get(ccd.account, []):
if ad.month_name == month:
tav_dict.actual += flt(ad.debit) - flt(ad.credit)
if ad.month_name == month and ad.fiscal_year == ccd.fiscal_year:
tav_dict.actual += flt(ad.debit) - flt(ad.credit)
return cam_map
def get_fiscal_years(filters):
fiscal_year = frappe.db.sql("""select name from `tabFiscal Year` where
name between %(from_fiscal_year)s and %(to_fiscal_year)s""",
{'from_fiscal_year': filters["from_fiscal_year"], 'to_fiscal_year': filters["to_fiscal_year"]})
fiscal_year = frappe.db.sql(
"""
select
name
from
`tabFiscal Year`
where
name between %(from_fiscal_year)s and %(to_fiscal_year)s
""",
{
"from_fiscal_year": filters["from_fiscal_year"],
"to_fiscal_year": filters["to_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

@ -84,6 +84,7 @@ def get_balance_sheet_data(fiscal_year, companies, columns, filters):
def get_profit_loss_data(fiscal_year, companies, columns, filters):
income, expense, net_profit_loss = get_income_expense_data(companies, fiscal_year, filters)
company_currency = get_company_currency(filters)
data = []
data.extend(income or [])
@ -93,7 +94,7 @@ def get_profit_loss_data(fiscal_year, companies, columns, filters):
chart = get_pl_chart_data(filters, columns, income, expense, net_profit_loss)
report_summary = get_pl_summary(companies, '', income, expense, net_profit_loss, True)
report_summary = get_pl_summary(companies, '', income, expense, net_profit_loss, company_currency, True)
return data, None, chart, report_summary

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
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}
Periodicity can be (Yearly, Quarterly, Monthly)"""
@ -67,8 +67,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
period.to_date = year_end_date
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]
if not ignore_fiscal_year:
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)

View File

@ -53,7 +53,7 @@ frappe.query_reports["General Ledger"] = {
"label": __("Voucher No"),
"fieldtype": "Data",
on_change: function() {
frappe.query_report.set_filter_value('group_by', "");
frappe.query_report.set_filter_value('group_by', "Group by Voucher (Consolidated)");
}
},
{
@ -154,8 +154,12 @@ frappe.query_reports["General Ledger"] = {
{
"fieldname": "include_default_book_entries",
"label": __("Include Default Book Entries"),
"fieldtype": "Check",
"default": 1
"fieldtype": "Check"
},
{
"fieldname": "show_cancelled_entries",
"label": __("Show Cancelled Entries"),
"fieldtype": "Check"
}
]
}

View File

@ -188,6 +188,9 @@ def get_conditions(filters):
else:
conditions.append("finance_book in (%(finance_book)s)")
if not filters.get("show_cancelled_entries"):
conditions.append("is_cancelled = 0")
from frappe.desk.reportview import build_match_conditions
match_conditions = build_match_conditions("GL Entry")
@ -293,6 +296,9 @@ def get_accountwise_gle(filters, gl_entries, gle_map):
data[key].debit_in_account_currency += flt(gle.debit_in_account_currency)
data[key].credit_in_account_currency += flt(gle.credit_in_account_currency)
if data[key].against_voucher and gle.against_voucher:
data[key].against_voucher += ', ' + gle.against_voucher
from_date, to_date = getdate(filters.from_date), getdate(filters.to_date)
for gle in gl_entries:
if (gle.posting_date < from_date or

View File

@ -9,8 +9,8 @@ from erpnext.accounts.report.financial_statements import (get_period_list, get_c
import copy
def execute(filters=None):
period_list = get_period_list(filters.from_fiscal_year, filters.to_fiscal_year,
filters.periodicity, filters.accumulated_values, filters.company)
period_list = get_period_list(filters.from_fiscal_year, filters.to_fiscal_year, filters.period_start_date,
filters.period_end_date, filters.filter_based_on, filters.periodicity, filters.accumulated_values, filters.company)
columns, data = [], []
@ -35,6 +35,12 @@ def execute(filters=None):
})
return columns, data
# to avoid error eg: gross_income[0] : list index out of range
if not gross_income:
gross_income = [{}]
if not gross_expense:
gross_expense = [{}]
data.append({
"account_name": "'" + _("Included in Gross Profit") + "'",
"account": "'" + _("Included in Gross Profit") + "'"

View File

@ -55,27 +55,27 @@ def get_columns(group_wise_columns, filters):
columns = []
column_map = frappe._dict({
"parent": _("Sales Invoice") + ":Link/Sales Invoice:120",
"posting_date": _("Posting Date") + ":Date",
"posting_time": _("Posting Time"),
"item_code": _("Item Code") + ":Link/Item",
"item_name": _("Item Name"),
"item_group": _("Item Group") + ":Link/Item Group",
"brand": _("Brand"),
"description": _("Description"),
"warehouse": _("Warehouse") + ":Link/Warehouse",
"qty": _("Qty") + ":Float",
"base_rate": _("Avg. Selling Rate") + ":Currency/currency",
"buying_rate": _("Valuation Rate") + ":Currency/currency",
"base_amount": _("Selling Amount") + ":Currency/currency",
"buying_amount": _("Buying Amount") + ":Currency/currency",
"gross_profit": _("Gross Profit") + ":Currency/currency",
"gross_profit_percent": _("Gross Profit %") + ":Percent",
"project": _("Project") + ":Link/Project",
"posting_date": _("Posting Date") + ":Date:100",
"posting_time": _("Posting Time") + ":Data:100",
"item_code": _("Item Code") + ":Link/Item:100",
"item_name": _("Item Name") + ":Data:100",
"item_group": _("Item Group") + ":Link/Item Group:100",
"brand": _("Brand") + ":Link/Brand:100",
"description": _("Description") +":Data:100",
"warehouse": _("Warehouse") + ":Link/Warehouse:100",
"qty": _("Qty") + ":Float:80",
"base_rate": _("Avg. Selling Rate") + ":Currency/currency:100",
"buying_rate": _("Valuation Rate") + ":Currency/currency:100",
"base_amount": _("Selling Amount") + ":Currency/currency:100",
"buying_amount": _("Buying Amount") + ":Currency/currency:100",
"gross_profit": _("Gross Profit") + ":Currency/currency:100",
"gross_profit_percent": _("Gross Profit %") + ":Percent:100",
"project": _("Project") + ":Link/Project:100",
"sales_person": _("Sales person"),
"allocated_amount": _("Allocated Amount") + ":Currency/currency",
"customer": _("Customer") + ":Link/Customer",
"customer_group": _("Customer Group") + ":Link/Customer Group",
"territory": _("Territory") + ":Link/Territory"
"allocated_amount": _("Allocated Amount") + ":Currency/currency:100",
"customer": _("Customer") + ":Link/Customer:100",
"customer_group": _("Customer Group") + ":Link/Customer Group:100",
"territory": _("Territory") + ":Link/Territory:100"
})
for col in group_wise_columns.get(scrub(filters.group_by)):
@ -85,7 +85,8 @@ def get_columns(group_wise_columns, filters):
"fieldname": "currency",
"label" : _("Currency"),
"fieldtype": "Link",
"options": "Currency"
"options": "Currency",
"hidden": 1
})
return columns
@ -277,7 +278,7 @@ class GrossProfitGenerator(object):
from `tabPurchase Invoice Item` a
where a.item_code = %s and a.docstatus=1
and modified <= %s
order by a.modified desc limit 1""", (item_code,self.filters.to_date))
order by a.modified desc limit 1""", (item_code, self.filters.to_date))
else:
last_purchase_rate = frappe.db.sql("""
select (a.base_rate / a.conversion_factor)

View File

@ -102,7 +102,7 @@ def _execute(filters=None, additional_table_columns=None, additional_query_colum
data.append(row)
if filters.get('group_by'):
if filters.get('group_by') and item_list:
total_row = total_row_map.get(prev_group_by_value or d.get('item_name'))
total_row['percent_gt'] = flt(total_row['total']/grand_total * 100)
data.append(total_row)

View File

@ -111,7 +111,7 @@ def _execute(filters=None, additional_table_columns=None, additional_query_colum
data.append(row)
if filters.get('group_by'):
if filters.get('group_by') and item_list:
total_row = total_row_map.get(prev_group_by_value or d.get('item_name'))
total_row['percent_gt'] = flt(total_row['total']/grand_total * 100)
data.append(total_row)

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

@ -111,7 +111,7 @@ def get_gle_map(filters):
# {"purchase_invoice": list of dict of all gle created for this invoice}
gle_map = {}
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"])
for d in gle:

View File

@ -46,7 +46,7 @@ frappe.require("assets/erpnext/js/financial_statements.js", function() {
"default": frappe.defaults.get_user_default("year_end_date"),
},
{
"fieldname":"cost_center",
"fieldname": "cost_center",
"label": __("Cost Center"),
"fieldtype": "Link",
"options": "Cost Center",
@ -61,7 +61,13 @@ frappe.require("assets/erpnext/js/financial_statements.js", function() {
}
},
{
"fieldname":"finance_book",
"fieldname": "project",
"label": __("Project"),
"fieldtype": "Link",
"options": "Project"
},
{
"fieldname": "finance_book",
"label": __("Finance Book"),
"fieldtype": "Link",
"options": "Finance Book",
@ -97,7 +103,7 @@ frappe.require("assets/erpnext/js/financial_statements.js", function() {
}
erpnext.dimension_filters.forEach((dimension) => {
frappe.query_reports["Trial Balance"].filters.splice(5, 0 ,{
frappe.query_reports["Trial Balance"].filters.splice(6, 0 ,{
"fieldname": dimension["fieldname"],
"label": __(dimension["label"]),
"fieldtype": "Link",

View File

@ -69,6 +69,11 @@ def get_data(filters):
gl_entries_by_account = {}
opening_balances = get_opening_balances(filters)
#add filter inside list so that the query in financial_statements.py doesn't break
if filters.project:
filters.project = [filters.project]
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))
@ -102,6 +107,9 @@ def get_rootwise_opening_balances(filters, report_type):
additional_conditions += """ and cost_center in (select name from `tabCost Center`
where lft >= %s and rgt <= %s)""" % (lft, rgt)
if filters.project:
additional_conditions += " and project = %(project)s"
if filters.finance_book:
fb_conditions = " AND finance_book = %(finance_book)s"
if filters.include_default_book_entries:
@ -116,6 +124,7 @@ def get_rootwise_opening_balances(filters, report_type):
"from_date": filters.from_date,
"report_type": report_type,
"year_start_date": filters.year_start_date,
"project": filters.project,
"finance_book": filters.finance_book,
"company_fb": frappe.db.get_value("Company", filters.company, 'default_finance_book')
}

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