mirror of
https://github.com/frappe/erpnext.git
synced 2026-06-06 13:49:13 +00:00
Fixed merge conflict
This commit is contained in:
@@ -2,9 +2,9 @@ from __future__ import unicode_literals
|
||||
|
||||
import frappe
|
||||
from frappe import _
|
||||
from frappe.utils import date_diff, add_months, today, getdate, add_days, flt
|
||||
from frappe.utils import date_diff, add_months, today, getdate, add_days, flt, get_last_day
|
||||
from erpnext.accounts.utils import get_account_currency
|
||||
from erpnext.accounts.general_ledger import make_gl_entries
|
||||
from frappe.email import sendmail_to_system_managers
|
||||
|
||||
def validate_service_stop_date(doc):
|
||||
''' Validates service_stop_date for Purchase Invoice and Sales Invoice '''
|
||||
@@ -33,47 +33,49 @@ def validate_service_stop_date(doc):
|
||||
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):
|
||||
# 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:
|
||||
end_date = add_days(today(), -1)
|
||||
|
||||
# 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
|
||||
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 or today(), start_date or add_months(today(), -1)))
|
||||
''', (end_date, start_date))
|
||||
|
||||
# For each invoice, book deferred expense
|
||||
for invoice in invoices:
|
||||
doc = frappe.get_doc("Purchase Invoice", invoice)
|
||||
book_deferred_income_or_expense(doc, start_date, end_date)
|
||||
book_deferred_income_or_expense(doc, end_date)
|
||||
|
||||
def convert_deferred_revenue_to_income(start_date=None, end_date=None):
|
||||
# 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:
|
||||
end_date = add_days(today(), -1)
|
||||
|
||||
# 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
|
||||
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 or today(), start_date or add_months(today(), -1)))
|
||||
''', (end_date, start_date))
|
||||
|
||||
# For each invoice, book deferred revenue
|
||||
for invoice in invoices:
|
||||
doc = frappe.get_doc("Sales Invoice", invoice)
|
||||
book_deferred_income_or_expense(doc, start_date, end_date)
|
||||
book_deferred_income_or_expense(doc, end_date)
|
||||
|
||||
def get_booking_dates(doc, item, posting_date=None):
|
||||
if not posting_date:
|
||||
posting_date = add_days(today(), -1)
|
||||
|
||||
last_gl_entry = False
|
||||
|
||||
def get_booking_dates(doc, item, start_date=None, end_date=None):
|
||||
deferred_account = "deferred_revenue_account" if doc.doctype=="Sales Invoice" else "deferred_expense_account"
|
||||
last_gl_entry, skip = False, False
|
||||
|
||||
booking_end_date = getdate(add_days(today(), -1) if not end_date else end_date)
|
||||
if booking_end_date < item.service_start_date or \
|
||||
(item.service_stop_date and booking_end_date.month > item.service_stop_date.month):
|
||||
return None, None, None, True
|
||||
elif booking_end_date >= item.service_end_date:
|
||||
last_gl_entry = True
|
||||
booking_end_date = item.service_end_date
|
||||
elif item.service_stop_date and item.service_stop_date <= booking_end_date:
|
||||
last_gl_entry = True
|
||||
booking_end_date = item.service_stop_date
|
||||
|
||||
booking_start_date = getdate(add_months(today(), -1) if not start_date else start_date)
|
||||
booking_start_date = booking_start_date \
|
||||
if booking_start_date > item.service_start_date else item.service_start_date
|
||||
|
||||
prev_gl_entry = frappe.db.sql('''
|
||||
select name, posting_date from `tabGL Entry` where company=%s and account=%s and
|
||||
@@ -81,17 +83,28 @@ def get_booking_dates(doc, item, start_date=None, end_date=None):
|
||||
order by posting_date desc limit 1
|
||||
''', (doc.company, item.get(deferred_account), doc.doctype, doc.name, item.name), as_dict=True)
|
||||
|
||||
if not prev_gl_entry and item.service_start_date < booking_start_date:
|
||||
booking_start_date = item.service_start_date
|
||||
elif prev_gl_entry:
|
||||
booking_start_date = getdate(add_days(prev_gl_entry[0].posting_date, 1))
|
||||
skip = True if booking_start_date > booking_end_date else False
|
||||
if prev_gl_entry:
|
||||
start_date = getdate(add_days(prev_gl_entry[0].posting_date, 1))
|
||||
else:
|
||||
start_date = item.service_start_date
|
||||
|
||||
return last_gl_entry, booking_start_date, booking_end_date, skip
|
||||
end_date = get_last_day(start_date)
|
||||
if end_date >= item.service_end_date:
|
||||
end_date = item.service_end_date
|
||||
last_gl_entry = True
|
||||
elif item.service_stop_date and end_date >= item.service_stop_date:
|
||||
end_date = item.service_stop_date
|
||||
last_gl_entry = True
|
||||
|
||||
def calculate_amount_and_base_amount(doc, item, last_gl_entry, total_days, total_booking_days):
|
||||
account_currency = get_account_currency(item.expense_account)
|
||||
if end_date > getdate(posting_date):
|
||||
end_date = posting_date
|
||||
|
||||
if getdate(start_date) <= getdate(end_date):
|
||||
return start_date, end_date, last_gl_entry
|
||||
else:
|
||||
return None, None, None
|
||||
|
||||
def calculate_amount(doc, item, last_gl_entry, total_days, total_booking_days, account_currency):
|
||||
if doc.doctype == "Sales Invoice":
|
||||
total_credit_debit, total_credit_debit_currency = "debit", "debit_in_account_currency"
|
||||
deferred_account = "deferred_revenue_account"
|
||||
@@ -123,28 +136,15 @@ def calculate_amount_and_base_amount(doc, item, last_gl_entry, total_days, total
|
||||
|
||||
return amount, base_amount
|
||||
|
||||
def book_deferred_income_or_expense(doc, start_date=None, end_date=None):
|
||||
# book the expense/income on the last day, but it will be trigger on the 1st of month at 12:00 AM
|
||||
# start_date: 1st of the last month or the start date
|
||||
# end_date: end_date or today-1
|
||||
def book_deferred_income_or_expense(doc, posting_date=None):
|
||||
enable_check = "enable_deferred_revenue" \
|
||||
if doc.doctype=="Sales Invoice" else "enable_deferred_expense"
|
||||
|
||||
gl_entries = []
|
||||
for item in doc.get('items'):
|
||||
if not item.get(enable_check): continue
|
||||
|
||||
skip = False
|
||||
last_gl_entry, booking_start_date, booking_end_date, skip = \
|
||||
get_booking_dates(doc, item, start_date, end_date)
|
||||
|
||||
if skip: continue
|
||||
total_days = date_diff(item.service_end_date, item.service_start_date) + 1
|
||||
total_booking_days = date_diff(booking_end_date, booking_start_date) + 1
|
||||
def _book_deferred_revenue_or_expense(item):
|
||||
start_date, end_date, last_gl_entry = get_booking_dates(doc, item, posting_date=posting_date)
|
||||
if not (start_date and end_date): return
|
||||
|
||||
account_currency = get_account_currency(item.expense_account)
|
||||
amount, base_amount = calculate_amount_and_base_amount(doc, item, last_gl_entry, total_days, total_booking_days)
|
||||
|
||||
if doc.doctype == "Sales Invoice":
|
||||
against, project = doc.customer, doc.project
|
||||
credit_account, debit_account = item.income_account, item.deferred_revenue_account
|
||||
@@ -152,36 +152,62 @@ def book_deferred_income_or_expense(doc, start_date=None, end_date=None):
|
||||
against, project = doc.supplier, item.project
|
||||
credit_account, debit_account = item.deferred_expense_account, item.expense_account
|
||||
|
||||
# GL Entry for crediting the amount in the deferred expense
|
||||
gl_entries.append(
|
||||
doc.get_gl_dict({
|
||||
"account": credit_account,
|
||||
"against": against,
|
||||
"credit": base_amount,
|
||||
"credit_in_account_currency": amount,
|
||||
"cost_center": item.cost_center,
|
||||
"voucher_detail_no": item.name,
|
||||
'posting_date': booking_end_date,
|
||||
'project': project
|
||||
}, account_currency)
|
||||
)
|
||||
# GL Entry to debit the amount from the expense
|
||||
gl_entries.append(
|
||||
doc.get_gl_dict({
|
||||
"account": debit_account,
|
||||
"against": against,
|
||||
"debit": base_amount,
|
||||
"debit_in_account_currency": amount,
|
||||
"cost_center": item.cost_center,
|
||||
"voucher_detail_no": item.name,
|
||||
'posting_date': booking_end_date,
|
||||
'project': project
|
||||
}, account_currency)
|
||||
)
|
||||
total_days = date_diff(item.service_end_date, item.service_start_date) + 1
|
||||
total_booking_days = date_diff(end_date, start_date) + 1
|
||||
|
||||
amount, base_amount = calculate_amount(doc, item, last_gl_entry,
|
||||
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)
|
||||
|
||||
if getdate(end_date) < getdate(posting_date) and not last_gl_entry:
|
||||
_book_deferred_revenue_or_expense(item)
|
||||
|
||||
|
||||
for item in doc.get('items'):
|
||||
if item.get(enable_check):
|
||||
_book_deferred_revenue_or_expense(item)
|
||||
|
||||
def make_gl_entries(doc, credit_account, debit_account, against,
|
||||
amount, base_amount, posting_date, project, account_currency, cost_center, voucher_detail_no):
|
||||
# GL Entry for crediting the amount in the deferred expense
|
||||
from erpnext.accounts.general_ledger import make_gl_entries
|
||||
|
||||
gl_entries = []
|
||||
gl_entries.append(
|
||||
doc.get_gl_dict({
|
||||
"account": credit_account,
|
||||
"against": against,
|
||||
"credit": base_amount,
|
||||
"credit_in_account_currency": amount,
|
||||
"cost_center": cost_center,
|
||||
"voucher_detail_no": voucher_detail_no,
|
||||
'posting_date': posting_date,
|
||||
'project': project
|
||||
}, account_currency)
|
||||
)
|
||||
# GL Entry to debit the amount from the expense
|
||||
gl_entries.append(
|
||||
doc.get_gl_dict({
|
||||
"account": debit_account,
|
||||
"against": against,
|
||||
"debit": base_amount,
|
||||
"debit_in_account_currency": amount,
|
||||
"cost_center": cost_center,
|
||||
"voucher_detail_no": voucher_detail_no,
|
||||
'posting_date': posting_date,
|
||||
'project': project
|
||||
}, account_currency)
|
||||
)
|
||||
|
||||
if gl_entries:
|
||||
try:
|
||||
make_gl_entries(gl_entries, cancel=(doc.docstatus == 2), merge_entries=True)
|
||||
frappe.db.commit()
|
||||
except:
|
||||
frappe.db.rollback()
|
||||
frappe.log_error(message = frappe.get_traceback(), title = _("Error while processing deferred accounting for {0}").format(doc.name))
|
||||
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)
|
||||
@@ -98,6 +98,8 @@ class Account(NestedSet):
|
||||
|
||||
ancestors = get_root_company(self.company)
|
||||
if ancestors:
|
||||
if frappe.get_value("Company", self.company, "allow_account_creation_against_child_company"):
|
||||
return
|
||||
frappe.throw(_("Please add the account to root level Company - %s" % ancestors[0]))
|
||||
else:
|
||||
descendants = get_descendants_of('Company', self.company)
|
||||
@@ -110,6 +112,8 @@ class Account(NestedSet):
|
||||
["company", "name"], as_dict=True):
|
||||
acc_name_map[d["company"]] = d["name"]
|
||||
|
||||
if not acc_name_map: return
|
||||
|
||||
for company in descendants:
|
||||
doc = frappe.copy_doc(self)
|
||||
doc.flags.ignore_root_company_validation = True
|
||||
|
||||
@@ -23,6 +23,10 @@ frappe.treeview_settings["Account"] = {
|
||||
if(r.message) {
|
||||
let root_company = r.message.length ? r.message[0] : "";
|
||||
me.page.fields_dict.root_company.set_value(root_company);
|
||||
|
||||
frappe.db.get_value("Company", {"name": company}, "allow_account_creation_against_child_company", (r) => {
|
||||
frappe.flags.ignore_root_company_validation = r.allow_account_creation_against_child_company;
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
@@ -133,9 +137,10 @@ frappe.treeview_settings["Account"] = {
|
||||
{
|
||||
label:__("Add Child"),
|
||||
condition: function(node) {
|
||||
return frappe.boot.user.can_create.indexOf("Account") !== -1 &&
|
||||
!frappe.treeview_settings['Account'].treeview.page.fields_dict.root_company.get_value() &&
|
||||
node.expandable && !node.hide_add;
|
||||
return frappe.boot.user.can_create.indexOf("Account") !== -1
|
||||
&& (!frappe.treeview_settings['Account'].treeview.page.fields_dict.root_company.get_value()
|
||||
|| frappe.flags.ignore_root_company_validation)
|
||||
&& node.expandable && !node.hide_add;
|
||||
},
|
||||
click: function() {
|
||||
var me = frappe.treeview_settings['Account'].treeview;
|
||||
|
||||
@@ -144,7 +144,7 @@ def _make_test_records(verbose):
|
||||
|
||||
# related to Account Inventory Integration
|
||||
["_Test Account Stock In Hand", "Current Assets", 0, None, None],
|
||||
|
||||
|
||||
# fixed asset depreciation
|
||||
["_Test Fixed Asset", "Current Assets", 0, "Fixed Asset", None],
|
||||
["_Test Accumulated Depreciations", "Current Assets", 0, None, None],
|
||||
@@ -181,13 +181,17 @@ def get_inventory_account(company, warehouse=None):
|
||||
return account
|
||||
|
||||
def create_account(**kwargs):
|
||||
account = frappe.get_doc(dict(
|
||||
doctype = "Account",
|
||||
account_name = kwargs.get('account_name'),
|
||||
account_type = kwargs.get('account_type'),
|
||||
parent_account = kwargs.get('parent_account'),
|
||||
company = kwargs.get('company')
|
||||
))
|
||||
|
||||
account.save()
|
||||
return account.name
|
||||
account = frappe.db.get_value("Account", filters={"account_name": kwargs.get("account_name"), "company": kwargs.get("company")})
|
||||
if account:
|
||||
return account
|
||||
else:
|
||||
account = frappe.get_doc(dict(
|
||||
doctype = "Account",
|
||||
account_name = kwargs.get('account_name'),
|
||||
account_type = kwargs.get('account_type'),
|
||||
parent_account = kwargs.get('parent_account'),
|
||||
company = kwargs.get('company')
|
||||
))
|
||||
|
||||
account.save()
|
||||
return account.name
|
||||
|
||||
@@ -23,36 +23,36 @@ class BankReconciliation(Document):
|
||||
|
||||
|
||||
journal_entries = frappe.db.sql("""
|
||||
select
|
||||
"Journal Entry" as payment_document, t1.name as payment_entry,
|
||||
t1.cheque_no as cheque_number, t1.cheque_date,
|
||||
select
|
||||
"Journal Entry" as payment_document, t1.name as payment_entry,
|
||||
t1.cheque_no as cheque_number, t1.cheque_date,
|
||||
sum(t2.debit_in_account_currency) as debit, sum(t2.credit_in_account_currency) as credit,
|
||||
t1.posting_date, t2.against_account, t1.clearance_date, t2.account_currency
|
||||
t1.posting_date, t2.against_account, t1.clearance_date, t2.account_currency
|
||||
from
|
||||
`tabJournal Entry` t1, `tabJournal Entry Account` t2
|
||||
where
|
||||
t2.parent = t1.name and t2.account = %s and t1.docstatus=1
|
||||
and t1.posting_date >= %s and t1.posting_date <= %s
|
||||
and t1.posting_date >= %s and t1.posting_date <= %s
|
||||
and ifnull(t1.is_opening, 'No') = 'No' {0}
|
||||
group by t2.account, t1.name
|
||||
order by t1.posting_date ASC, t1.name DESC
|
||||
""".format(condition), (self.bank_account, self.from_date, self.to_date), as_dict=1)
|
||||
|
||||
payment_entries = frappe.db.sql("""
|
||||
select
|
||||
"Payment Entry" as payment_document, name as payment_entry,
|
||||
reference_no as cheque_number, reference_date as cheque_date,
|
||||
if(paid_from=%(account)s, paid_amount, "") as credit,
|
||||
if(paid_from=%(account)s, "", received_amount) as debit,
|
||||
select
|
||||
"Payment Entry" as payment_document, name as payment_entry,
|
||||
reference_no as cheque_number, reference_date as cheque_date,
|
||||
if(paid_from=%(account)s, paid_amount, 0) as credit,
|
||||
if(paid_from=%(account)s, 0, received_amount) as debit,
|
||||
posting_date, ifnull(party,if(paid_from=%(account)s,paid_to,paid_from)) as against_account, clearance_date,
|
||||
if(paid_to=%(account)s, paid_to_account_currency, paid_from_account_currency) as account_currency
|
||||
from `tabPayment Entry`
|
||||
where
|
||||
(paid_from=%(account)s or paid_to=%(account)s) and docstatus=1
|
||||
and posting_date >= %(from)s and posting_date <= %(to)s {0}
|
||||
order by
|
||||
order by
|
||||
posting_date ASC, name DESC
|
||||
""".format(condition),
|
||||
""".format(condition),
|
||||
{"account":self.bank_account, "from":self.from_date, "to":self.to_date}, as_dict=1)
|
||||
|
||||
pos_entries = []
|
||||
@@ -79,8 +79,12 @@ class BankReconciliation(Document):
|
||||
|
||||
for d in entries:
|
||||
row = self.append('payment_entries', {})
|
||||
amount = d.debit if d.debit else d.credit
|
||||
d.amount = fmt_money(amount, 2, d.account_currency) + " " + (_("Dr") if d.debit else _("Cr"))
|
||||
|
||||
amount = flt(d.get('debit', 0)) - flt(d.get('credit', 0))
|
||||
|
||||
formatted_amount = fmt_money(abs(amount), 2, d.account_currency)
|
||||
d.amount = formatted_amount + " " + (_("Dr") if amount > 0 else _("Cr"))
|
||||
|
||||
d.pop("credit")
|
||||
d.pop("debit")
|
||||
d.pop("account_currency")
|
||||
@@ -103,10 +107,10 @@ class BankReconciliation(Document):
|
||||
d.clearance_date = None
|
||||
|
||||
frappe.db.set_value(d.payment_document, d.payment_entry, "clearance_date", d.clearance_date)
|
||||
frappe.db.sql("""update `tab{0}` set clearance_date = %s, modified = %s
|
||||
where name=%s""".format(d.payment_document),
|
||||
frappe.db.sql("""update `tab{0}` set clearance_date = %s, modified = %s
|
||||
where name=%s""".format(d.payment_document),
|
||||
(d.clearance_date, nowdate(), d.payment_entry))
|
||||
|
||||
|
||||
clearance_date_updated = True
|
||||
|
||||
if clearance_date_updated:
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
{
|
||||
"allow_copy": 0,
|
||||
"allow_events_in_timeline": 0,
|
||||
"allow_guest_to_view": 0,
|
||||
"allow_import": 1,
|
||||
"allow_rename": 0,
|
||||
@@ -19,6 +20,7 @@
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"default": "Cost Center",
|
||||
"fetch_if_empty": 0,
|
||||
"fieldname": "budget_against",
|
||||
"fieldtype": "Select",
|
||||
"hidden": 0,
|
||||
@@ -52,6 +54,7 @@
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fetch_if_empty": 0,
|
||||
"fieldname": "company",
|
||||
"fieldtype": "Link",
|
||||
"hidden": 0,
|
||||
@@ -86,6 +89,7 @@
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"depends_on": "eval:doc.budget_against == 'Cost Center'",
|
||||
"fetch_if_empty": 0,
|
||||
"fieldname": "cost_center",
|
||||
"fieldtype": "Link",
|
||||
"hidden": 0,
|
||||
@@ -120,6 +124,7 @@
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"depends_on": "eval:doc.budget_against == 'Project'",
|
||||
"fetch_if_empty": 0,
|
||||
"fieldname": "project",
|
||||
"fieldtype": "Link",
|
||||
"hidden": 0,
|
||||
@@ -153,6 +158,7 @@
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fetch_if_empty": 0,
|
||||
"fieldname": "fiscal_year",
|
||||
"fieldtype": "Link",
|
||||
"hidden": 0,
|
||||
@@ -186,6 +192,7 @@
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fetch_if_empty": 0,
|
||||
"fieldname": "column_break_3",
|
||||
"fieldtype": "Column Break",
|
||||
"hidden": 0,
|
||||
@@ -218,6 +225,7 @@
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"depends_on": "eval:in_list([\"Stop\", \"Warn\"], doc.action_if_accumulated_monthly_budget_exceeded_on_po || doc.action_if_accumulated_monthly_budget_exceeded_on_mr || doc.action_if_accumulated_monthly_budget_exceeded_on_actual)",
|
||||
"fetch_if_empty": 0,
|
||||
"fieldname": "monthly_distribution",
|
||||
"fieldtype": "Link",
|
||||
"hidden": 0,
|
||||
@@ -251,6 +259,7 @@
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fetch_if_empty": 0,
|
||||
"fieldname": "amended_from",
|
||||
"fieldtype": "Link",
|
||||
"hidden": 0,
|
||||
@@ -283,6 +292,7 @@
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fetch_if_empty": 0,
|
||||
"fieldname": "section_break_6",
|
||||
"fieldtype": "Section Break",
|
||||
"hidden": 0,
|
||||
@@ -315,6 +325,7 @@
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fetch_if_empty": 0,
|
||||
"fieldname": "applicable_on_material_request",
|
||||
"fieldtype": "Check",
|
||||
"hidden": 0,
|
||||
@@ -343,12 +354,13 @@
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_in_quick_entry": 0,
|
||||
"allow_on_submit": 0,
|
||||
"allow_on_submit": 1,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"default": "Stop",
|
||||
"depends_on": "eval:doc.applicable_on_material_request == 1",
|
||||
"fetch_if_empty": 0,
|
||||
"fieldname": "action_if_annual_budget_exceeded_on_mr",
|
||||
"fieldtype": "Select",
|
||||
"hidden": 0,
|
||||
@@ -378,12 +390,13 @@
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_in_quick_entry": 0,
|
||||
"allow_on_submit": 0,
|
||||
"allow_on_submit": 1,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"default": "Warn",
|
||||
"depends_on": "eval:doc.applicable_on_material_request == 1",
|
||||
"fetch_if_empty": 0,
|
||||
"fieldname": "action_if_accumulated_monthly_budget_exceeded_on_mr",
|
||||
"fieldtype": "Select",
|
||||
"hidden": 0,
|
||||
@@ -417,6 +430,7 @@
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fetch_if_empty": 0,
|
||||
"fieldname": "column_break_13",
|
||||
"fieldtype": "Column Break",
|
||||
"hidden": 0,
|
||||
@@ -448,6 +462,7 @@
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fetch_if_empty": 0,
|
||||
"fieldname": "applicable_on_purchase_order",
|
||||
"fieldtype": "Check",
|
||||
"hidden": 0,
|
||||
@@ -476,12 +491,13 @@
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_in_quick_entry": 0,
|
||||
"allow_on_submit": 0,
|
||||
"allow_on_submit": 1,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"default": "Stop",
|
||||
"depends_on": "eval:doc.applicable_on_purchase_order == 1",
|
||||
"fetch_if_empty": 0,
|
||||
"fieldname": "action_if_annual_budget_exceeded_on_po",
|
||||
"fieldtype": "Select",
|
||||
"hidden": 0,
|
||||
@@ -511,12 +527,13 @@
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_in_quick_entry": 0,
|
||||
"allow_on_submit": 0,
|
||||
"allow_on_submit": 1,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"default": "Warn",
|
||||
"depends_on": "eval:doc.applicable_on_purchase_order == 1",
|
||||
"fetch_if_empty": 0,
|
||||
"fieldname": "action_if_accumulated_monthly_budget_exceeded_on_po",
|
||||
"fieldtype": "Select",
|
||||
"hidden": 0,
|
||||
@@ -550,6 +567,7 @@
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fetch_if_empty": 0,
|
||||
"fieldname": "section_break_16",
|
||||
"fieldtype": "Section Break",
|
||||
"hidden": 0,
|
||||
@@ -581,6 +599,7 @@
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fetch_if_empty": 0,
|
||||
"fieldname": "applicable_on_booking_actual_expenses",
|
||||
"fieldtype": "Check",
|
||||
"hidden": 0,
|
||||
@@ -609,12 +628,13 @@
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_in_quick_entry": 0,
|
||||
"allow_on_submit": 0,
|
||||
"allow_on_submit": 1,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"default": "Stop",
|
||||
"depends_on": "eval:doc.applicable_on_booking_actual_expenses == 1",
|
||||
"fetch_if_empty": 0,
|
||||
"fieldname": "action_if_annual_budget_exceeded",
|
||||
"fieldtype": "Select",
|
||||
"hidden": 0,
|
||||
@@ -644,12 +664,13 @@
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_in_quick_entry": 0,
|
||||
"allow_on_submit": 0,
|
||||
"allow_on_submit": 1,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"default": "Warn",
|
||||
"depends_on": "eval:doc.applicable_on_booking_actual_expenses == 1",
|
||||
"fetch_if_empty": 0,
|
||||
"fieldname": "action_if_accumulated_monthly_budget_exceeded",
|
||||
"fieldtype": "Select",
|
||||
"hidden": 0,
|
||||
@@ -683,6 +704,7 @@
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fetch_if_empty": 0,
|
||||
"fieldname": "section_break_21",
|
||||
"fieldtype": "Section Break",
|
||||
"hidden": 0,
|
||||
@@ -715,6 +737,7 @@
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"depends_on": "",
|
||||
"fetch_if_empty": 0,
|
||||
"fieldname": "accounts",
|
||||
"fieldtype": "Table",
|
||||
"hidden": 0,
|
||||
@@ -735,7 +758,7 @@
|
||||
"read_only": 0,
|
||||
"remember_last_selected_value": 0,
|
||||
"report_hide": 0,
|
||||
"reqd": 1,
|
||||
"reqd": 1,
|
||||
"search_index": 0,
|
||||
"set_only_once": 0,
|
||||
"translatable": 0,
|
||||
@@ -752,7 +775,7 @@
|
||||
"issingle": 0,
|
||||
"istable": 0,
|
||||
"max_attachments": 0,
|
||||
"modified": "2018-09-12 11:02:41.825923",
|
||||
"modified": "2019-03-22 12:06:02.323099",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Accounts",
|
||||
"name": "Budget",
|
||||
@@ -785,7 +808,7 @@
|
||||
"show_name_in_global_search": 0,
|
||||
"sort_field": "modified",
|
||||
"sort_order": "DESC",
|
||||
"track_changes": 1,
|
||||
"track_seen": 0,
|
||||
"track_changes": 1,
|
||||
"track_seen": 0,
|
||||
"track_views": 0
|
||||
}
|
||||
@@ -6,6 +6,7 @@ import frappe, erpnext
|
||||
from frappe import _
|
||||
from frappe.utils import flt, fmt_money, getdate, formatdate
|
||||
from frappe.model.document import Document
|
||||
from frappe.model.meta import get_field_precision
|
||||
from erpnext.accounts.party import validate_party_gle_currency, validate_party_frozen_disabled
|
||||
from erpnext.accounts.utils import get_account_currency
|
||||
from erpnext.accounts.utils import get_fiscal_year
|
||||
@@ -56,7 +57,7 @@ class GLEntry(Document):
|
||||
.format(self.voucher_type, self.voucher_no, self.account))
|
||||
|
||||
# Zero value transaction is not allowed
|
||||
if not (flt(self.debit) or flt(self.credit)):
|
||||
if not (flt(self.debit, self.precision("debit")) or flt(self.credit, self.precision("credit"))):
|
||||
frappe.throw(_("{0} {1}: Either debit or credit amount is required for {2}")
|
||||
.format(self.voucher_type, self.voucher_no, self.account))
|
||||
|
||||
@@ -216,17 +217,23 @@ def validate_frozen_account(account, adv_adj=None):
|
||||
def update_against_account(voucher_type, voucher_no):
|
||||
entries = frappe.db.get_all("GL Entry",
|
||||
filters={"voucher_type": voucher_type, "voucher_no": voucher_no},
|
||||
fields=["name", "party", "against", "debit", "credit", "account"])
|
||||
fields=["name", "party", "against", "debit", "credit", "account", "company"])
|
||||
|
||||
if not entries:
|
||||
return
|
||||
company_currency = erpnext.get_company_currency(entries[0].company)
|
||||
precision = get_field_precision(frappe.get_meta("GL Entry")
|
||||
.get_field("debit"), company_currency)
|
||||
|
||||
accounts_debited, accounts_credited = [], []
|
||||
for d in entries:
|
||||
if flt(d.debit > 0): accounts_debited.append(d.party or d.account)
|
||||
if flt(d.credit) > 0: accounts_credited.append(d.party or d.account)
|
||||
if flt(d.debit, precision) > 0: accounts_debited.append(d.party or d.account)
|
||||
if flt(d.credit, precision) > 0: accounts_credited.append(d.party or d.account)
|
||||
|
||||
for d in entries:
|
||||
if flt(d.debit > 0):
|
||||
if flt(d.debit, precision) > 0:
|
||||
new_against = ", ".join(list(set(accounts_credited)))
|
||||
if flt(d.credit > 0):
|
||||
if flt(d.credit, precision) > 0:
|
||||
new_against = ", ".join(list(set(accounts_debited)))
|
||||
|
||||
if d.against != new_against:
|
||||
|
||||
@@ -52,11 +52,6 @@ class JournalEntry(AccountsController):
|
||||
self.update_loan()
|
||||
self.update_inter_company_jv()
|
||||
|
||||
def before_print(self):
|
||||
self.gl_entries = frappe.get_list("GL Entry",filters={"voucher_type": "Journal Entry",
|
||||
"voucher_no": self.name} ,
|
||||
fields=["account", "party_type", "party", "debit", "credit", "remarks"]
|
||||
)
|
||||
|
||||
def get_title(self):
|
||||
return self.pay_to_recd_from or self.accounts[0].account
|
||||
|
||||
@@ -232,6 +232,13 @@ frappe.ui.form.on('Payment Entry', {
|
||||
},
|
||||
|
||||
party_type: function(frm) {
|
||||
|
||||
let party_types = Object.keys(frappe.boot.party_account_types);
|
||||
if(frm.doc.party_type && !party_types.includes(frm.doc.party_type)){
|
||||
frm.set_value("party_type", "");
|
||||
frappe.throw(__("Party can only be one of "+ party_types.join(", ")));
|
||||
}
|
||||
|
||||
if(frm.doc.party) {
|
||||
$.each(["party", "party_balance", "paid_from", "paid_to",
|
||||
"paid_from_account_currency", "paid_from_account_balance",
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -70,11 +70,6 @@ class PaymentEntry(AccountsController):
|
||||
self.update_advance_paid()
|
||||
self.update_expense_claim()
|
||||
|
||||
def before_print(self):
|
||||
self.gl_entries = frappe.get_list("GL Entry",filters={"voucher_type": "Payment Entry",
|
||||
"voucher_no": self.name} ,
|
||||
fields=["account", "party_type", "party", "debit", "credit", "remarks"]
|
||||
)
|
||||
|
||||
def on_cancel(self):
|
||||
self.setup_party_account_field()
|
||||
@@ -541,9 +536,13 @@ class PaymentEntry(AccountsController):
|
||||
|
||||
@frappe.whitelist()
|
||||
def get_outstanding_reference_documents(args):
|
||||
|
||||
if isinstance(args, string_types):
|
||||
args = json.loads(args)
|
||||
|
||||
if args.get('party_type') == 'Member':
|
||||
return
|
||||
|
||||
# confirm that Supplier is not blocked
|
||||
if args.get('party_type') == 'Supplier':
|
||||
supplier_status = get_supplier_block_status(args['party'])
|
||||
@@ -754,7 +753,7 @@ def get_outstanding_on_journal_entry(name):
|
||||
|
||||
@frappe.whitelist()
|
||||
def get_reference_details(reference_doctype, reference_name, party_account_currency):
|
||||
total_amount = outstanding_amount = exchange_rate = None
|
||||
total_amount = outstanding_amount = exchange_rate = bill_no = None
|
||||
ref_doc = frappe.get_doc(reference_doctype, reference_name)
|
||||
company_currency = ref_doc.get("company_currency") or erpnext.get_company_currency(ref_doc.company)
|
||||
|
||||
@@ -788,6 +787,7 @@ def get_reference_details(reference_doctype, reference_name, party_account_curre
|
||||
|
||||
if reference_doctype in ("Sales Invoice", "Purchase Invoice"):
|
||||
outstanding_amount = ref_doc.get("outstanding_amount")
|
||||
bill_no = ref_doc.get("bill_no")
|
||||
elif reference_doctype == "Expense Claim":
|
||||
outstanding_amount = flt(ref_doc.get("total_sanctioned_amount")) \
|
||||
- flt(ref_doc.get("total_amount+reimbursed")) - flt(ref_doc.get("total_advance_amount"))
|
||||
@@ -804,7 +804,8 @@ def get_reference_details(reference_doctype, reference_name, party_account_curre
|
||||
"due_date": ref_doc.get("due_date"),
|
||||
"total_amount": total_amount,
|
||||
"outstanding_amount": outstanding_amount,
|
||||
"exchange_rate": exchange_rate
|
||||
"exchange_rate": exchange_rate,
|
||||
"bill_no": bill_no
|
||||
})
|
||||
|
||||
|
||||
|
||||
@@ -13,20 +13,20 @@ class PaymentReconciliation(Document):
|
||||
def get_unreconciled_entries(self):
|
||||
self.get_nonreconciled_payment_entries()
|
||||
self.get_invoice_entries()
|
||||
|
||||
|
||||
def get_nonreconciled_payment_entries(self):
|
||||
self.check_mandatory_to_fetch()
|
||||
|
||||
|
||||
payment_entries = self.get_payment_entries()
|
||||
journal_entries = self.get_jv_entries()
|
||||
|
||||
|
||||
self.add_payment_entries(payment_entries + journal_entries)
|
||||
|
||||
|
||||
def get_payment_entries(self):
|
||||
order_doctype = "Sales Order" if self.party_type=="Customer" else "Purchase Order"
|
||||
payment_entries = get_advance_payment_entries(self.party_type, self.party,
|
||||
payment_entries = get_advance_payment_entries(self.party_type, self.party,
|
||||
self.receivable_payable_account, order_doctype, against_all_orders=True, limit=self.limit)
|
||||
|
||||
|
||||
return payment_entries
|
||||
|
||||
def get_jv_entries(self):
|
||||
@@ -36,12 +36,12 @@ class PaymentReconciliation(Document):
|
||||
bank_account_condition = "t2.against_account like %(bank_cash_account)s" \
|
||||
if self.bank_cash_account else "1=1"
|
||||
|
||||
limit_cond = "limit %s" % (self.limit or 1000)
|
||||
limit_cond = "limit %s" % self.limit if self.limit else ""
|
||||
|
||||
journal_entries = frappe.db.sql("""
|
||||
select
|
||||
"Journal Entry" as reference_type, t1.name as reference_name,
|
||||
t1.posting_date, t1.remark as remarks, t2.name as reference_row,
|
||||
"Journal Entry" as reference_type, t1.name as reference_name,
|
||||
t1.posting_date, t1.remark as remarks, t2.name as reference_row,
|
||||
{dr_or_cr} as amount, t2.is_advance
|
||||
from
|
||||
`tabJournal Entry` t1, `tabJournal Entry Account` t2
|
||||
@@ -49,8 +49,8 @@ class PaymentReconciliation(Document):
|
||||
t1.name = t2.parent and t1.docstatus = 1 and t2.docstatus = 1
|
||||
and t2.party_type = %(party_type)s and t2.party = %(party)s
|
||||
and t2.account = %(account)s and {dr_or_cr} > 0
|
||||
and (t2.reference_type is null or t2.reference_type = '' or
|
||||
(t2.reference_type in ('Sales Order', 'Purchase Order')
|
||||
and (t2.reference_type is null or t2.reference_type = '' or
|
||||
(t2.reference_type in ('Sales Order', 'Purchase Order')
|
||||
and t2.reference_name is not null and t2.reference_name != ''))
|
||||
and (CASE
|
||||
WHEN t1.voucher_type in ('Debit Note', 'Credit Note')
|
||||
@@ -83,7 +83,10 @@ class PaymentReconciliation(Document):
|
||||
condition = self.check_condition()
|
||||
|
||||
non_reconciled_invoices = get_outstanding_invoices(self.party_type, self.party,
|
||||
self.receivable_payable_account, condition=condition, limit=self.limit)
|
||||
self.receivable_payable_account, condition=condition)
|
||||
|
||||
if self.limit:
|
||||
non_reconciled_invoices = non_reconciled_invoices[:self.limit]
|
||||
|
||||
self.add_invoice_entries(non_reconciled_invoices)
|
||||
|
||||
@@ -109,7 +112,7 @@ class PaymentReconciliation(Document):
|
||||
self.validate_invoice()
|
||||
dr_or_cr = ("credit_in_account_currency"
|
||||
if erpnext.get_party_account_type(self.party_type) == 'Receivable' else "debit_in_account_currency")
|
||||
|
||||
|
||||
lst = []
|
||||
for e in self.get('payments'):
|
||||
if e.invoice_number and e.allocated_amount:
|
||||
@@ -127,11 +130,11 @@ class PaymentReconciliation(Document):
|
||||
'unadjusted_amount' : flt(e.amount),
|
||||
'allocated_amount' : flt(e.allocated_amount)
|
||||
}))
|
||||
|
||||
|
||||
if lst:
|
||||
from erpnext.accounts.utils import reconcile_against_document
|
||||
reconcile_against_document(lst)
|
||||
|
||||
|
||||
msgprint(_("Successfully Reconciled"))
|
||||
self.get_unreconciled_entries()
|
||||
|
||||
|
||||
@@ -214,9 +214,10 @@ class PaymentRequest(Document):
|
||||
|
||||
def check_if_payment_entry_exists(self):
|
||||
if self.status == "Paid":
|
||||
payment_entry = frappe.db.sql_list("""select parent from `tabPayment Entry Reference`
|
||||
where reference_name=%s""", self.reference_name)
|
||||
if payment_entry:
|
||||
if frappe.get_all("Payment Entry Reference",
|
||||
filters={"reference_name": self.reference_name, "docstatus": ["<", 2]},
|
||||
fields=["parent"],
|
||||
limit=1):
|
||||
frappe.throw(_("Payment Entry already exists"), title=_('Error'))
|
||||
|
||||
def make_communication_entry(self):
|
||||
|
||||
@@ -468,7 +468,7 @@ cur_frm.fields_dict["items"].grid.get_field("cost_center").get_query = function(
|
||||
|
||||
cur_frm.cscript.cost_center = function(doc, cdt, cdn){
|
||||
var d = locals[cdt][cdn];
|
||||
if(d.idx == 1 && d.cost_center){
|
||||
if(d.cost_center){
|
||||
var cl = doc.items || [];
|
||||
for(var i = 0; i < cl.length; i++){
|
||||
if(!cl[i].cost_center) cl[i].cost_center = d.cost_center;
|
||||
@@ -510,11 +510,25 @@ frappe.ui.form.on("Purchase Invoice", {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
frm.set_query("cost_center", function() {
|
||||
return {
|
||||
filters: {
|
||||
company: frm.doc.company,
|
||||
is_group: 0
|
||||
}
|
||||
};
|
||||
});
|
||||
},
|
||||
|
||||
onload: function(frm) {
|
||||
if(frm.doc.__onload && !frm.doc.__onload.supplier_tds) {
|
||||
me.frm.set_df_property("apply_tds", "read_only", 1);
|
||||
if(frm.doc.__onload) {
|
||||
if(frm.doc.supplier) {
|
||||
frm.doc.apply_tds = frm.doc.__onload.supplier_tds ? 1 : 0;
|
||||
}
|
||||
if(!frm.doc.__onload.supplier_tds) {
|
||||
frm.set_df_property("apply_tds", "read_only", 1);
|
||||
}
|
||||
}
|
||||
|
||||
erpnext.queries.setup_queries(frm, "Warehouse", function() {
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -55,11 +55,6 @@ class PurchaseInvoice(BuyingController):
|
||||
if not self.on_hold:
|
||||
self.release_date = ''
|
||||
|
||||
def before_print(self):
|
||||
self.gl_entries = frappe.get_list("GL Entry",filters={"voucher_type": "Purchase Invoice",
|
||||
"voucher_no": self.name} ,
|
||||
fields=["account", "party_type", "party", "debit", "credit"]
|
||||
)
|
||||
|
||||
def invoice_is_blocked(self):
|
||||
return self.on_hold and (not self.release_date or self.release_date > getdate(nowdate()))
|
||||
@@ -223,7 +218,7 @@ class PurchaseInvoice(BuyingController):
|
||||
self.validate_item_code()
|
||||
self.validate_warehouse()
|
||||
if auto_accounting_for_stock:
|
||||
warehouse_account = get_warehouse_account_map()
|
||||
warehouse_account = get_warehouse_account_map(self.company)
|
||||
|
||||
for item in self.get("items"):
|
||||
# in case of auto inventory accounting,
|
||||
@@ -374,7 +369,8 @@ class PurchaseInvoice(BuyingController):
|
||||
if 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)
|
||||
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)
|
||||
@@ -433,7 +429,7 @@ class PurchaseInvoice(BuyingController):
|
||||
stock_items = self.get_stock_items()
|
||||
expenses_included_in_valuation = self.get_company_default("expenses_included_in_valuation")
|
||||
if self.update_stock and self.auto_accounting_for_stock:
|
||||
warehouse_account = get_warehouse_account_map()
|
||||
warehouse_account = get_warehouse_account_map(self.company)
|
||||
|
||||
voucher_wise_stock_value = {}
|
||||
if self.update_stock:
|
||||
@@ -793,9 +789,8 @@ class PurchaseInvoice(BuyingController):
|
||||
for d in self.items:
|
||||
if d.project and d.project not in project_list:
|
||||
project = frappe.get_doc("Project", d.project)
|
||||
project.flags.dont_sync_tasks = True
|
||||
project.update_purchase_costing()
|
||||
project.save()
|
||||
project.db_update()
|
||||
project_list.append(d.project)
|
||||
|
||||
def validate_supplier_invoice(self):
|
||||
|
||||
@@ -344,6 +344,7 @@ class TestPurchaseInvoice(unittest.TestCase):
|
||||
|
||||
pi = frappe.copy_doc(test_records[0])
|
||||
pi.disable_rounded_total = 1
|
||||
pi.allocate_advances_automatically = 0
|
||||
pi.append("advances", {
|
||||
"reference_type": "Journal Entry",
|
||||
"reference_name": jv.name,
|
||||
@@ -383,6 +384,7 @@ class TestPurchaseInvoice(unittest.TestCase):
|
||||
|
||||
pi = frappe.copy_doc(test_records[0])
|
||||
pi.disable_rounded_total = 1
|
||||
pi.allocate_advances_automatically = 0
|
||||
pi.append("advances", {
|
||||
"reference_type": "Journal Entry",
|
||||
"reference_name": jv.name,
|
||||
@@ -551,7 +553,7 @@ class TestPurchaseInvoice(unittest.TestCase):
|
||||
sum(credit) as credit, debit_in_account_currency, credit_in_account_currency
|
||||
from `tabGL Entry` where voucher_type='Purchase Invoice' and voucher_no=%s
|
||||
group by account, voucher_no order by account asc;""", pi.name, as_dict=1)
|
||||
|
||||
|
||||
stock_in_hand_account = get_inventory_account(pi.company, pi.get("items")[0].warehouse)
|
||||
self.assertTrue(gl_entries)
|
||||
|
||||
@@ -634,7 +636,7 @@ class TestPurchaseInvoice(unittest.TestCase):
|
||||
|
||||
self.assertEqual(frappe.db.get_value("Serial No", pi.get("items")[0].rejected_serial_no,
|
||||
"warehouse"), pi.get("items")[0].rejected_warehouse)
|
||||
|
||||
|
||||
def test_outstanding_amount_after_advance_jv_cancelation(self):
|
||||
from erpnext.accounts.doctype.journal_entry.test_journal_entry \
|
||||
import test_records as jv_test_records
|
||||
@@ -656,14 +658,14 @@ class TestPurchaseInvoice(unittest.TestCase):
|
||||
pi.insert()
|
||||
pi.submit()
|
||||
pi.load_from_db()
|
||||
|
||||
|
||||
#check outstanding after advance allocation
|
||||
self.assertEqual(flt(pi.outstanding_amount), flt(pi.rounded_total - pi.total_advance))
|
||||
|
||||
|
||||
#added to avoid Document has been modified exception
|
||||
jv = frappe.get_doc("Journal Entry", jv.name)
|
||||
jv.cancel()
|
||||
|
||||
|
||||
pi.load_from_db()
|
||||
#check outstanding after advance cancellation
|
||||
self.assertEqual(flt(pi.outstanding_amount), flt(pi.rounded_total + pi.total_advance))
|
||||
@@ -722,7 +724,7 @@ class TestPurchaseInvoice(unittest.TestCase):
|
||||
shipping_rule = create_shipping_rule(shipping_rule_type = "Buying", shipping_rule_name = "Shipping Rule - Purchase Invoice Test")
|
||||
|
||||
pi = frappe.copy_doc(test_records[0])
|
||||
|
||||
|
||||
pi.shipping_rule = shipping_rule.name
|
||||
pi.insert()
|
||||
|
||||
@@ -740,14 +742,14 @@ class TestPurchaseInvoice(unittest.TestCase):
|
||||
"tax_amount": shipping_amount,
|
||||
"description": shipping_rule.name,
|
||||
"add_deduct_tax": "Add"
|
||||
}
|
||||
}
|
||||
pi.append("taxes", shipping_charge)
|
||||
pi.save()
|
||||
|
||||
self.assertEqual(pi.net_total, 1250)
|
||||
|
||||
self.assertEqual(pi.total_taxes_and_charges, 462.3)
|
||||
self.assertEqual(pi.grand_total, 1712.3)
|
||||
self.assertEqual(pi.grand_total, 1712.3)
|
||||
|
||||
def test_make_pi_without_terms(self):
|
||||
pi = make_purchase_invoice(do_not_save=1)
|
||||
|
||||
@@ -564,6 +564,15 @@ frappe.ui.form.on('Sales Invoice', {
|
||||
};
|
||||
});
|
||||
|
||||
frm.set_query("cost_center", function() {
|
||||
return {
|
||||
filters: {
|
||||
company: frm.doc.company,
|
||||
is_group: 0
|
||||
}
|
||||
};
|
||||
});
|
||||
|
||||
frm.custom_make_buttons = {
|
||||
'Delivery Note': 'Delivery',
|
||||
'Sales Invoice': 'Sales Return',
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -205,11 +205,6 @@ class SalesInvoice(SellingController):
|
||||
def before_cancel(self):
|
||||
self.update_time_sheet(None)
|
||||
|
||||
def before_print(self):
|
||||
self.gl_entries = frappe.get_list("GL Entry",filters={"voucher_type": "Sales Invoice",
|
||||
"voucher_no": self.name} ,
|
||||
fields=["account", "party_type", "party", "debit", "credit"]
|
||||
)
|
||||
|
||||
def on_cancel(self):
|
||||
self.check_close_sales_order("sales_order")
|
||||
@@ -405,7 +400,7 @@ class SalesInvoice(SellingController):
|
||||
|
||||
for fieldname in ('territory', 'naming_series', 'currency', 'taxes_and_charges', 'letter_head', 'tc_name',
|
||||
'company', 'select_print_heading', 'cash_bank_account', 'company_address',
|
||||
'write_off_account', 'write_off_cost_center', 'apply_discount_on'):
|
||||
'write_off_account', 'write_off_cost_center', 'apply_discount_on', 'cost_center'):
|
||||
if (not for_validate) or (for_validate and not self.get(fieldname)):
|
||||
self.set(fieldname, pos.get(fieldname))
|
||||
|
||||
@@ -695,7 +690,8 @@ class SalesInvoice(SellingController):
|
||||
if 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)
|
||||
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
|
||||
@@ -1026,9 +1022,8 @@ class SalesInvoice(SellingController):
|
||||
def update_project(self):
|
||||
if self.project:
|
||||
project = frappe.get_doc("Project", self.project)
|
||||
project.flags.dont_sync_tasks = True
|
||||
project.update_billed_amount()
|
||||
project.save()
|
||||
project.db_update()
|
||||
|
||||
|
||||
def verify_payment_amount_is_positive(self):
|
||||
|
||||
@@ -14,8 +14,9 @@ from erpnext.stock.doctype.purchase_receipt.test_purchase_receipt import set_per
|
||||
from erpnext.exceptions import InvalidAccountCurrency, InvalidCurrency
|
||||
from erpnext.stock.doctype.serial_no.serial_no import SerialNoWarehouseError
|
||||
from frappe.model.naming import make_autoname
|
||||
from erpnext.accounts.doctype.account.test_account import get_inventory_account
|
||||
from erpnext.accounts.doctype.account.test_account import get_inventory_account, create_account
|
||||
from erpnext.controllers.taxes_and_totals import get_itemised_tax_breakup_data
|
||||
from erpnext.stock.doctype.item.test_item import create_item
|
||||
from six import iteritems
|
||||
class TestSalesInvoice(unittest.TestCase):
|
||||
def make(self):
|
||||
@@ -762,7 +763,7 @@ class TestSalesInvoice(unittest.TestCase):
|
||||
set_perpetual_inventory(0)
|
||||
|
||||
frappe.db.sql("delete from `tabPOS Profile`")
|
||||
|
||||
|
||||
def test_pos_si_without_payment(self):
|
||||
set_perpetual_inventory()
|
||||
make_pos_profile()
|
||||
@@ -854,6 +855,7 @@ class TestSalesInvoice(unittest.TestCase):
|
||||
jv.submit()
|
||||
|
||||
si = frappe.copy_doc(test_records[0])
|
||||
si.allocate_advances_automatically = 0
|
||||
si.append("advances", {
|
||||
"doctype": "Sales Invoice Advance",
|
||||
"reference_type": "Journal Entry",
|
||||
@@ -1360,7 +1362,7 @@ class TestSalesInvoice(unittest.TestCase):
|
||||
"included_in_print_rate": 1
|
||||
})
|
||||
si.save()
|
||||
|
||||
si.submit()
|
||||
self.assertEqual(si.net_total, 19453.13)
|
||||
self.assertEqual(si.grand_total, 24900)
|
||||
self.assertEqual(si.total_taxes_and_charges, 5446.88)
|
||||
@@ -1382,6 +1384,50 @@ class TestSalesInvoice(unittest.TestCase):
|
||||
self.assertEqual(expected_values[gle.account][1], gle.debit)
|
||||
self.assertEqual(expected_values[gle.account][2], gle.credit)
|
||||
|
||||
def test_rounding_adjustment_2(self):
|
||||
si = create_sales_invoice(rate=400, do_not_save=True)
|
||||
for rate in [400, 600, 100]:
|
||||
si.append("items", {
|
||||
"item_code": "_Test Item",
|
||||
"gst_hsn_code": "999800",
|
||||
"warehouse": "_Test Warehouse - _TC",
|
||||
"qty": 1,
|
||||
"rate": rate,
|
||||
"income_account": "Sales - _TC",
|
||||
"cost_center": "_Test Cost Center - _TC"
|
||||
})
|
||||
for tax_account in ["_Test Account VAT - _TC", "_Test Account Service Tax - _TC"]:
|
||||
si.append("taxes", {
|
||||
"charge_type": "On Net Total",
|
||||
"account_head": tax_account,
|
||||
"description": tax_account,
|
||||
"rate": 9,
|
||||
"cost_center": "_Test Cost Center - _TC",
|
||||
"included_in_print_rate": 1
|
||||
})
|
||||
si.save()
|
||||
si.submit()
|
||||
self.assertEqual(si.net_total, 1271.19)
|
||||
self.assertEqual(si.grand_total, 1500)
|
||||
self.assertEqual(si.total_taxes_and_charges, 228.82)
|
||||
self.assertEqual(si.rounding_adjustment, -0.01)
|
||||
|
||||
expected_values = dict((d[0], d) for d in [
|
||||
[si.debit_to, 1500, 0.0],
|
||||
["_Test Account Service Tax - _TC", 0.0, 114.41],
|
||||
["_Test Account VAT - _TC", 0.0, 114.41],
|
||||
["Sales - _TC", 0.0, 1271.18]
|
||||
])
|
||||
|
||||
gl_entries = frappe.db.sql("""select account, debit, credit
|
||||
from `tabGL Entry` where voucher_type='Sales Invoice' and voucher_no=%s
|
||||
order by account asc""", si.name, as_dict=1)
|
||||
|
||||
for gle in gl_entries:
|
||||
self.assertEqual(expected_values[gle.account][0], gle.account)
|
||||
self.assertEqual(expected_values[gle.account][1], gle.debit)
|
||||
self.assertEqual(expected_values[gle.account][2], gle.credit)
|
||||
|
||||
def test_sales_invoice_with_shipping_rule(self):
|
||||
from erpnext.accounts.doctype.shipping_rule.test_shipping_rule \
|
||||
import create_shipping_rule
|
||||
@@ -1514,6 +1560,56 @@ class TestSalesInvoice(unittest.TestCase):
|
||||
accounts_settings.allow_cost_center_in_entry_of_bs_account = 0
|
||||
accounts_settings.save()
|
||||
|
||||
def test_deferred_revenue(self):
|
||||
deferred_account = create_account(account_name="Deferred Revenue",
|
||||
parent_account="Current Liabilities - _TC", company="_Test Company")
|
||||
|
||||
item = create_item("_Test Item for Deferred Accounting")
|
||||
item.enable_deferred_revenue = 1
|
||||
item.deferred_revenue_account = deferred_account
|
||||
item.no_of_months = 12
|
||||
item.save()
|
||||
|
||||
si = create_sales_invoice(item=item.name, posting_date="2019-01-10", do_not_submit=True)
|
||||
si.items[0].enable_deferred_revenue = 1
|
||||
si.items[0].service_start_date = "2019-01-10"
|
||||
si.items[0].service_end_date = "2019-03-15"
|
||||
si.items[0].deferred_revenue_account = deferred_account
|
||||
si.save()
|
||||
si.submit()
|
||||
|
||||
from erpnext.accounts.deferred_revenue import convert_deferred_revenue_to_income
|
||||
convert_deferred_revenue_to_income(start_date="2019-01-01", end_date="2019-01-31")
|
||||
|
||||
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 = [
|
||||
[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")
|
||||
|
||||
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)
|
||||
|
||||
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)
|
||||
|
||||
def create_sales_invoice(**args):
|
||||
si = frappe.new_doc("Sales Invoice")
|
||||
@@ -1611,4 +1707,4 @@ def get_outstanding_amount(against_voucher_type, against_voucher, account, party
|
||||
if against_voucher_type == 'Purchase Invoice':
|
||||
bal = bal * -1
|
||||
|
||||
return bal
|
||||
return bal
|
||||
@@ -135,9 +135,9 @@ def round_off_debit_credit(gl_map):
|
||||
.format(gl_map[0].voucher_type, gl_map[0].voucher_no, debit_credit_diff))
|
||||
|
||||
elif abs(debit_credit_diff) >= (1.0 / (10**precision)):
|
||||
make_round_off_gle(gl_map, debit_credit_diff)
|
||||
make_round_off_gle(gl_map, debit_credit_diff, precision)
|
||||
|
||||
def make_round_off_gle(gl_map, debit_credit_diff):
|
||||
def make_round_off_gle(gl_map, debit_credit_diff, precision):
|
||||
round_off_account, round_off_cost_center = get_round_off_account_and_cost_center(gl_map[0].company)
|
||||
round_off_account_exists = False
|
||||
round_off_gle = frappe._dict()
|
||||
@@ -150,6 +150,10 @@ def make_round_off_gle(gl_map, debit_credit_diff):
|
||||
debit_credit_diff += flt(d.credit_in_account_currency)
|
||||
round_off_account_exists = True
|
||||
|
||||
if round_off_account_exists and abs(debit_credit_diff) <= (1.0 / (10**precision)):
|
||||
gl_map.remove(round_off_gle)
|
||||
return
|
||||
|
||||
if not round_off_gle:
|
||||
for k in ["voucher_type", "voucher_no", "company",
|
||||
"posting_date", "remarks", "is_opening"]:
|
||||
|
||||
@@ -333,6 +333,7 @@ erpnext.pos.PointOfSale = erpnext.taxes_and_totals.extend({
|
||||
var me = this;
|
||||
this.frm = {}
|
||||
this.load_data(true);
|
||||
this.frm.doc.offline_pos_name = '';
|
||||
this.setup();
|
||||
this.set_default_customer()
|
||||
},
|
||||
@@ -345,7 +346,6 @@ erpnext.pos.PointOfSale = erpnext.taxes_and_totals.extend({
|
||||
|
||||
if (load_doc) {
|
||||
this.frm.doc = JSON.parse(localStorage.getItem('doc'));
|
||||
this.frm.doc.offline_pos_name = null;
|
||||
}
|
||||
|
||||
$.each(this.meta, function (i, data) {
|
||||
@@ -641,7 +641,7 @@ erpnext.pos.PointOfSale = erpnext.taxes_and_totals.extend({
|
||||
me.list_customers_btn.toggleClass("view_customer");
|
||||
me.pos_bill.show();
|
||||
me.list_customers_btn.show();
|
||||
me.frm.doc.offline_pos_name = $(this).parents().attr('invoice-name')
|
||||
me.frm.doc.offline_pos_name = $(this).parents().attr('invoice-name');
|
||||
me.edit_record();
|
||||
})
|
||||
|
||||
@@ -984,7 +984,7 @@ erpnext.pos.PointOfSale = erpnext.taxes_and_totals.extend({
|
||||
}
|
||||
|
||||
if(!this.customer_doc.fields_dict.customer_pos_id.value) {
|
||||
this.customer_doc.set_value("customer_pos_id", $.now())
|
||||
this.customer_doc.set_value("customer_pos_id", frappe.datetime.now_datetime())
|
||||
}
|
||||
},
|
||||
|
||||
@@ -1686,10 +1686,18 @@ erpnext.pos.PointOfSale = erpnext.taxes_and_totals.extend({
|
||||
|
||||
create_invoice: function () {
|
||||
var me = this;
|
||||
var existing_pos_list = [];
|
||||
var invoice_data = {};
|
||||
this.si_docs = this.get_doc_from_localstorage();
|
||||
|
||||
if (this.frm.doc.offline_pos_name) {
|
||||
if(this.si_docs) {
|
||||
this.si_docs.forEach((row) => {
|
||||
existing_pos_list.push(Object.keys(row));
|
||||
});
|
||||
}
|
||||
|
||||
if (this.frm.doc.offline_pos_name
|
||||
&& in_list(existing_pos_list, this.frm.doc.offline_pos_name)) {
|
||||
this.update_invoice()
|
||||
//to retrieve and set the default payment
|
||||
invoice_data[this.frm.doc.offline_pos_name] = this.frm.doc;
|
||||
@@ -1698,8 +1706,8 @@ erpnext.pos.PointOfSale = erpnext.taxes_and_totals.extend({
|
||||
|
||||
this.frm.doc.paid_amount = this.frm.doc.net_total
|
||||
this.frm.doc.outstanding_amount = 0
|
||||
} else {
|
||||
this.frm.doc.offline_pos_name = $.now();
|
||||
} else if(!this.frm.doc.offline_pos_name) {
|
||||
this.frm.doc.offline_pos_name = frappe.datetime.now_datetime();
|
||||
this.frm.doc.posting_date = frappe.datetime.get_today();
|
||||
this.frm.doc.posting_time = frappe.datetime.now_time();
|
||||
this.frm.doc.pos_total_qty = this.frm.doc.qty_total;
|
||||
|
||||
@@ -573,11 +573,17 @@ def get_party_shipping_address(doctype, name):
|
||||
else:
|
||||
return ''
|
||||
|
||||
def get_partywise_advanced_payment_amount(party_type="Customer"):
|
||||
def get_partywise_advanced_payment_amount(party_type, posting_date = None):
|
||||
cond = "1=1"
|
||||
if posting_date:
|
||||
cond = "posting_date <= '{0}'".format(posting_date)
|
||||
|
||||
data = frappe.db.sql(""" SELECT party, sum({0}) as amount
|
||||
FROM `tabGL Entry`
|
||||
WHERE party_type = %s and against_voucher is null GROUP BY party"""
|
||||
.format(("credit - debit") if party_type == "Customer" else "debit") , party_type)
|
||||
WHERE
|
||||
party_type = %s and against_voucher is null
|
||||
and {1} GROUP BY party"""
|
||||
.format(("credit") if party_type == "Customer" else "debit", cond) , party_type)
|
||||
|
||||
if data:
|
||||
return frappe._dict(data)
|
||||
@@ -6,17 +6,18 @@
|
||||
|
||||
|
||||
</style>
|
||||
<div class="page-break">
|
||||
<div>
|
||||
{% set gl = frappe.get_list(doctype="GL Entry", fields=["account", "party_type", "party", "debit", "credit", "remarks"], filters={"voucher_type": doc.doctype, "voucher_no": doc.name}) %}
|
||||
{%- if not doc.get("print_heading") and not doc.get("select_print_heading")
|
||||
and doc.set("select_print_heading", _("Payment Entry")) -%}{%- endif -%}
|
||||
{{ add_header(0, 1, doc, letter_head, no_letterhead, print_settings) }}
|
||||
<div class="row margin-bottom">
|
||||
<div class="col-sm-6">
|
||||
<div class="col-xs-6">
|
||||
<table>
|
||||
<tr><td><strong>Voucher No: </strong></td><td>{{ doc.name }}</td></tr>
|
||||
</table>
|
||||
</div>
|
||||
<div>
|
||||
<div class="col-xs-6">
|
||||
<table>
|
||||
<tr><td><strong>Date: </strong></td><td>{{ frappe.utils.formatdate(doc.creation) }}</td></tr>
|
||||
</table>
|
||||
@@ -30,53 +31,46 @@
|
||||
<th>Party</th>
|
||||
<th>Amount</th>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="top-bottom" colspan="5"><strong>Debit</strong></td>
|
||||
</tr>
|
||||
{% for entries in gl %}
|
||||
{% if entries.credit == 0.0 %}
|
||||
<tr>
|
||||
<td class="right top-bottom">{{ entries.account }}</td>
|
||||
<td class="right left top-bottom">{{ entries.party_type }}</td>
|
||||
<td class="right left top-bottom">{{ entries.party }}</td>
|
||||
<td class="left top-bottom">{{ entries.debit }}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="top-bottom"colspan="4"><strong> Narration </strong><br>{{ entries.remarks }}</td>
|
||||
</tr>
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
<tr>
|
||||
<td class="right" colspan="3" ><strong>Total (debit) </strong></td>
|
||||
<td class="left" >{{ gl | sum(attribute='debit') }}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="top-bottom" colspan="5"><strong>Credit</strong></td>
|
||||
</tr>
|
||||
{% set total_credit = 0 -%}
|
||||
{% for entries in doc.gl_entries %}
|
||||
{% for entries in gl %}
|
||||
{% if entries.debit == 0.0 %}
|
||||
<tr>
|
||||
<td class="right top-bottom">{{ entries.account }}</td>
|
||||
<td class="right left top-bottom">{{ entries.party_type }}</td>
|
||||
<td class="right left top-bottom">{{ entries.party }}</td>
|
||||
<td class="left top-bottom">{{ entries.credit }}</td>
|
||||
{% set total_credit = total_credit + entries.credit -%}
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="top-bottom" colspan="4"><strong> Narration </strong><br>{{ entries.remarks }}</td>
|
||||
</tr>
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
<tr>
|
||||
<td class="right" colspan="3"><strong>Total (credit) </strong></td>
|
||||
<td class="left" >{{total_credit}}</td>
|
||||
<td class="left" >{{ gl | sum(attribute='credit') }}</td>
|
||||
</tr>
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
<tr>
|
||||
<td class="top-bottom" colspan="4"> </td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="top-bottom" colspan="5"><strong>Debit</strong></td>
|
||||
</tr>
|
||||
{% set total_debit = 0 -%}
|
||||
{% for entries in doc.gl_entries %}
|
||||
{% if entries.credit == 0.0 %}
|
||||
<tr>
|
||||
<td class="right top-bottom">{{ entries.account }}</td>
|
||||
<td class="right left top-bottom">{{ entries.party_type }}</td>
|
||||
<td class="right left top-bottom">{{ entries.party }}</td>
|
||||
{% set total_debit = total_debit + entries.debit -%}
|
||||
<td class="left top-bottom">{{ entries.debit }}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="top-bottom"colspan="4"><strong> Narration </strong><br>{{ entries.remarks }}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="right" colspan="3" ><strong>Total (debit) </strong></td>
|
||||
<td class="left" >{{total_debit}}</td>
|
||||
</tr>
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
</table>
|
||||
<div>
|
||||
</div>
|
||||
@@ -3,26 +3,25 @@
|
||||
.table-bordered td.top-bottom {border-top: none !important;border-bottom: none !important;}
|
||||
.table-bordered td.right{border-right: none !important;}
|
||||
.table-bordered td.left{border-left: none !important;}
|
||||
|
||||
|
||||
</style>
|
||||
<div class="page-break">
|
||||
<div>
|
||||
{% set gl = frappe.get_list(doctype="GL Entry", fields=["account", "party_type", "party", "debit", "credit", "remarks"], filters={"voucher_type": doc.doctype, "voucher_no": doc.name}) %}
|
||||
{%- if not doc.get("print_heading") and not doc.get("select_print_heading")
|
||||
and doc.set("select_print_heading", _("Journal Entry")) -%}{%- endif -%}
|
||||
{{ add_header(0, 1, doc, letter_head, no_letterhead, print_settings) }}
|
||||
<div class="row margin-bottom">
|
||||
<div class="col-sm-6">
|
||||
<div class="row">
|
||||
<div class="col-xs-6">
|
||||
<table>
|
||||
<tr><td><strong>Voucher No: </strong></td><td>{{ doc.name }}</td></tr>
|
||||
<tr><td><strong>Voucher No: </strong></td><td>{{ doc.name }}</td></tr>
|
||||
</table>
|
||||
</div>
|
||||
<div>
|
||||
<div class="col-xs-6">
|
||||
<table>
|
||||
<tr><td><strong>Date: </strong></td><td>{{ frappe.utils.formatdate(doc.creation) }}</td></tr>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
<div class="margin-top">
|
||||
<div>
|
||||
<table class="table table-bordered table-condensed">
|
||||
<tr>
|
||||
<th>Account</th>
|
||||
@@ -30,47 +29,43 @@
|
||||
<th>Party</th>
|
||||
<th>Amount</th>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="top-bottom" colspan="5"><strong>Debit</strong></td>
|
||||
</tr>
|
||||
{% for entries in gl %}
|
||||
{% if entries.credit == 0.0 %}
|
||||
<tr>
|
||||
<td class="right top-bottom">{{ entries.account }}</td>
|
||||
<td class="right left top-bottom">{{ entries.party_type }}</td>
|
||||
<td class="right left top-bottom">{{ entries.party }}</td>
|
||||
<td class="left top-bottom">{{ entries.debit }}</td>
|
||||
</tr>
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
<tr>
|
||||
<td class="right" colspan="3" ><strong>Total (debit) </strong></td>
|
||||
<td class="left" >{{ gl | sum(attribute='debit') }}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="top-bottom" colspan="5"><strong>Credit</strong></td>
|
||||
</tr>
|
||||
{% set total_credit = 0 -%}
|
||||
{% for entries in doc.gl_entries %}
|
||||
{% for entries in gl %}
|
||||
{% if entries.debit == 0.0 %}
|
||||
<tr>
|
||||
<td class="right top-bottom">{{ entries.account }}</td>
|
||||
<td class="right left top-bottom">{{ entries.party_type }}</td>
|
||||
<td class="right left top-bottom">{{ entries.party }}</td>
|
||||
<td class="left top-bottom">{{ entries.credit }}</td>
|
||||
{% set total_credit = total_credit + entries.credit -%}
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="right" colspan="3"><strong>Total (credit) </strong></td>
|
||||
<td class="left" >{{total_credit}}</td>
|
||||
</tr>
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
<tr>
|
||||
<td class="top-bottom" colspan="4"> </td>
|
||||
<td class="right" colspan="3"><strong>Total (credit) </strong></td>
|
||||
<td class="left" >{{ gl | sum(attribute='credit') }}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="top-bottom" colspan="5"><strong>Debit</strong></td>
|
||||
<td class="top-bottom" colspan="5"><b>Narration: </b>{{ gl[0].remarks }}</td>
|
||||
</tr>
|
||||
{% set total_debit = 0 -%}
|
||||
{% for entries in doc.gl_entries %}
|
||||
{% if entries.credit == 0.0 %}
|
||||
<tr>
|
||||
<td class="right top-bottom">{{ entries.account }}</td>
|
||||
<td class="right left top-bottom">{{ entries.party_type }}</td>
|
||||
<td class="right left top-bottom">{{ entries.party }}</td>
|
||||
{% set total_debit = total_debit + entries.debit -%}
|
||||
<td class="left top-bottom">{{ entries.debit }}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="right" colspan="3" ><strong>Total (debit) </strong></td>
|
||||
<td class="left" >{{total_debit}}</td>
|
||||
</tr>
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
</table>
|
||||
<div>
|
||||
</div>
|
||||
@@ -1,10 +1,11 @@
|
||||
{%- from "templates/print_formats/standard_macros.html" import add_header -%}
|
||||
<div class="page-break">
|
||||
<div>
|
||||
{% set gl = frappe.get_list(doctype="GL Entry", fields=["account", "party_type", "party", "debit", "credit", "remarks"], filters={"voucher_type": doc.doctype, "voucher_no": doc.name}) %}
|
||||
{%- if not doc.get("print_heading") and not doc.get("select_print_heading")
|
||||
and doc.set("select_print_heading", _("Purchase Invoice")) -%}{%- endif -%}
|
||||
{{ add_header(0, 1, doc, letter_head, no_letterhead, print_settings) }}
|
||||
<div class="row margin-bottom">
|
||||
<div class="col-sm-6">
|
||||
<div class="col-xs-6">
|
||||
<table>
|
||||
<tr><td><strong>Supplier Name: </strong></td><td>{{ doc.supplier }}</td></tr>
|
||||
<tr><td><strong>Due Date: </strong></td><td>{{ frappe.utils.formatdate(doc.due_date) }}</td></tr>
|
||||
@@ -13,7 +14,7 @@
|
||||
<tr><td><strong>Mobile no: </strong> </td><td>{{doc.contact_mobile}}</td></tr>
|
||||
</table>
|
||||
</div>
|
||||
<div>
|
||||
<div class="col-xs-6">
|
||||
<table>
|
||||
<tr><td><strong>Voucher No: </strong></td><td>{{ doc.name }}</td></tr>
|
||||
<tr><td><strong>Date: </strong></td><td>{{ frappe.utils.formatdate(doc.creation) }}</td></tr>
|
||||
@@ -49,21 +50,27 @@
|
||||
</table>
|
||||
</div>
|
||||
<div class="row margin-bottom">
|
||||
<div class="col-sm-6">
|
||||
<div class="col-xs-6">
|
||||
<table>
|
||||
<tr><td><strong>Total Quantity: </strong></td><td>{{ doc.total_qty }}</td></tr>
|
||||
<tr><td><strong>Total: </strong></td><td>{{doc.total}}</td></tr>
|
||||
<tr><td><strong>Net Weight: </strong></td><td>{{ doc.total_net_weight }}</td></tr>
|
||||
</table>
|
||||
</div>
|
||||
<div>
|
||||
<div class="col-xs-6">
|
||||
<table>
|
||||
<tr><td><strong>Tax and Charges: </strong></td><td>{{doc.taxes_and_charges}}</td></tr>
|
||||
{% for tax in doc.taxes %}
|
||||
<tr><td><strong>{{ tax.account_head }}: </strong></td><td>{{ tax.tax_amount_after_discount_amount }}</td></tr>
|
||||
{% if tax.tax_amount_after_discount_amount!= 0 %}
|
||||
<tr><td><strong>{{ tax.account_head }}: </strong></td><td>{{ tax.tax_amount_after_discount_amount }}</td></tr>
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
{% if doc.taxes_and_charges_added!= 0 %}
|
||||
<tr><td><strong> Taxes and Charges Added: </strong></td><td>{{ doc.taxes_and_charges_added }}</td></tr>
|
||||
{% endif %}
|
||||
{% if doc.taxes_and_charges_deducted!= 0 %}
|
||||
<tr><td><strong> Taxes and Charges Deducted: </strong></td><td>{{ doc.taxes_and_charges_deducted }}</td></tr>
|
||||
{% endif %}
|
||||
<tr><td><strong> Total Taxes and Charges: </strong></td><td>{{ doc.total_taxes_and_charges }}</td></tr>
|
||||
<tr><td><strong> Net Payable: </strong></td><td>{{ doc.grand_total }}</td></tr>
|
||||
</table>
|
||||
@@ -76,17 +83,17 @@
|
||||
<th>Account</th>
|
||||
<th>Party Type</th>
|
||||
<th>Party</th>
|
||||
<th>Credit Amount</th>
|
||||
<th>Debit Amount</th>
|
||||
<th>Credit Amount</th>
|
||||
</tr>
|
||||
{% for entries in doc.gl_entries %}
|
||||
{% for entries in gl %}
|
||||
<tr>
|
||||
<td>{{ loop.index }}</td>
|
||||
<td>{{ entries.account }}</td>
|
||||
<td>{{ entries.party_type }}</td>
|
||||
<td>{{ entries.party }}</td>
|
||||
<td>{{ entries.credit }}</td>
|
||||
<td>{{ entries.debit }}</td>
|
||||
<td>{{ entries.credit }}</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
<tr>
|
||||
|
||||
@@ -1,10 +1,11 @@
|
||||
{%- from "templates/print_formats/standard_macros.html" import add_header -%}
|
||||
<div class="page-break">
|
||||
<div>
|
||||
{% set gl = frappe.get_list(doctype="GL Entry", fields=["account", "party_type", "party", "debit", "credit", "remarks"], filters={"voucher_type": doc.doctype, "voucher_no": doc.name}) %}
|
||||
{%- if not doc.get("print_heading") and not doc.get("select_print_heading")
|
||||
and doc.set("select_print_heading", _("Sales Invoice")) -%}{%- endif -%}
|
||||
{{ add_header(0, 1, doc, letter_head, no_letterhead, print_settings) }}
|
||||
<div class="row margin-bottom">
|
||||
<div class="col-sm-6">
|
||||
<div class="col-xs-6">
|
||||
<table>
|
||||
<tr><td><strong>Customer Name: </strong></td><td>{{ doc.customer }}</td></tr>
|
||||
<tr><td><strong>Due Date: </strong></td><td>{{ frappe.utils.formatdate(doc.due_date) }}</td></tr>
|
||||
@@ -13,7 +14,7 @@
|
||||
<tr><td><strong>Mobile no: </strong> </td><td>{{doc.contact_mobile}}</td></tr>
|
||||
</table>
|
||||
</div>
|
||||
<div>
|
||||
<div class="col-xs-6">
|
||||
<table>
|
||||
<tr><td><strong>Voucher No: </strong></td><td>{{ doc.name }}</td></tr>
|
||||
<tr><td><strong>Date: </strong></td><td>{{ frappe.utils.formatdate(doc.creation) }}</td></tr>
|
||||
@@ -45,18 +46,20 @@
|
||||
</table>
|
||||
</div>
|
||||
<div class="row margin-bottom">
|
||||
<div class="col-sm-6">
|
||||
<div class="col-xs-6">
|
||||
<table>
|
||||
<tr><td><strong>Total Quantity: </strong></td><td>{{ doc.total_qty }}</td></tr>
|
||||
<tr><td><strong>Total: </strong></td><td>{{doc.total}}</td></tr>
|
||||
<tr><td><strong>Net Weight: </strong></td><td>{{ doc.total_net_weight }}</td></tr>
|
||||
</table>
|
||||
</div>
|
||||
<div>
|
||||
<div class="col-xs-6">
|
||||
<table>
|
||||
<tr><td><strong>Tax and Charges: </strong></td><td>{{doc.taxes_and_charges}}</td></tr>
|
||||
{% for tax in doc.taxes %}
|
||||
<tr><td><strong>{{ tax.account_head }}: </strong></td><td>{{ tax.tax_amount_after_discount_amount }}</td></tr>
|
||||
{% if tax.tax_amount_after_discount_amount!= 0 %}
|
||||
<tr><td><strong>{{ tax.account_head }}: </strong></td><td>{{ tax.tax_amount_after_discount_amount }}</td></tr>
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
<tr><td><strong> Total Taxes and Charges: </strong></td><td>{{ doc.total_taxes_and_charges }}</td></tr>
|
||||
<tr><td><strong> Net Payable: </strong></td><td>{{ doc.grand_total }}</td></tr>
|
||||
@@ -70,17 +73,17 @@
|
||||
<th>Account</th>
|
||||
<th>Party Type</th>
|
||||
<th>Party</th>
|
||||
<th>Credit Amount</th>
|
||||
<th>Debit Amount</th>
|
||||
<th>Credit Amount</th>
|
||||
</tr>
|
||||
{% for entries in doc.gl_entries %}
|
||||
{% for entries in gl %}
|
||||
<tr>
|
||||
<td>{{ loop.index }}</td>
|
||||
<td>{{ entries.account }}</td>
|
||||
<td>{{ entries.party_type }}</td>
|
||||
<td>{{ entries.party }}</td>
|
||||
<td>{{ entries.credit }}</td>
|
||||
<td>{{ entries.debit }}</td>
|
||||
<td>{{ entries.credit }}</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
<tr>
|
||||
|
||||
@@ -107,26 +107,28 @@
|
||||
<thead>
|
||||
<tr>
|
||||
{% if(report.report_name === "Accounts Receivable" || report.report_name === "Accounts Payable") { %}
|
||||
<th style="width: 7%">{%= __("Date") %}</th>
|
||||
<th style="width: 7%">{%= __("Age (Days)") %}</th>
|
||||
<th style="width: 13%">{%= __("Reference") %}</th>
|
||||
{% if(report.report_name === "Accounts Receivable") { %}
|
||||
<th style="width: 10%">{%= __("Sales Person") %}</th>
|
||||
<th style="width: 9%">{%= __("Date") %}</th>
|
||||
<th style="width: 5%">{%= __("Age (Days)") %}</th>
|
||||
|
||||
{% if(report.report_name === "Accounts Receivable" && filters.show_sales_person_in_print) { %}
|
||||
<th style="width: 16%">{%= __("Reference") %}</th>
|
||||
<th style="width: 10%">{%= __("Sales Person") %}</th>
|
||||
{% } else { %}
|
||||
<th style="width: 26%">{%= __("Reference") %}</th>
|
||||
{% } %}
|
||||
{% if(!filters.show_pdc_in_print) { %}
|
||||
<th style="width: 20%">{%= (filters.customer || filters.supplier) ? __("Remarks"): __("Party") %}</th>
|
||||
<th style="width: 20%">{%= (filters.customer || filters.supplier) ? __("Remarks"): __("Party") %}</th>
|
||||
{% } %}
|
||||
<th style="width: 10%; text-align: right">{%= __("Invoiced Amount") %}</th>
|
||||
{% if(!filters.show_pdc_in_print) { %}
|
||||
<th style="width: 10%; text-align: right">{%= __("Paid Amount") %}</th>
|
||||
<th style="width: 10%; text-align: right">{%= report.report_name === "Accounts Receivable" ? __('Credit Note') : __('Debit Note') %}</th>
|
||||
{% } %}
|
||||
<th style="width: 15%; text-align: right">{%= __("Outstanding Amount") %}</th>
|
||||
<th style="width: 10%; text-align: right">{%= __("Outstanding Amount") %}</th>
|
||||
{% if(filters.show_pdc_in_print) { %}
|
||||
{% if(report.report_name === "Accounts Receivable") { %}
|
||||
<th style="width: 10%">{%= __("Customer LPO No.") %}</th>
|
||||
{% } %}
|
||||
<th style="width: 10%">{%= __("PDC/LC Date") %}</th>
|
||||
<th style="width: 10%">{%= __("PDC/LC Ref") %}</th>
|
||||
<th style="width: 10%">{%= __("PDC/LC Amount") %}</th>
|
||||
<th style="width: 10%">{%= __("Remaining Balance") %}</th>
|
||||
@@ -155,7 +157,7 @@
|
||||
{%= data[i]["voucher_no"] %}
|
||||
</td>
|
||||
|
||||
{% if(report.report_name === "Accounts Receivable") { %}
|
||||
{% if(report.report_name === "Accounts Receivable" && filters.show_sales_person_in_print) { %}
|
||||
<td>{%= data[i]["sales_person"] %}</td>
|
||||
{% } %}
|
||||
|
||||
@@ -195,7 +197,6 @@
|
||||
<td style="text-align: right">
|
||||
{%= data[i]["po_no"] %}</td>
|
||||
{% } %}
|
||||
<td style="text-align: right">{%= frappe.datetime.str_to_user(data[i][("pdc/lc_date")]) %}</td>
|
||||
<td style="text-align: right">{%= data[i][("pdc/lc_ref")] %}</td>
|
||||
<td style="text-align: right">{%= format_currency(data[i][("pdc/lc_amount")], data[i]["currency"]) %}</td>
|
||||
<td style="text-align: right">{%= format_currency(data[i][("remaining_balance")], data[i]["currency"]) %}</td>
|
||||
@@ -226,7 +227,6 @@
|
||||
<td style="text-align: right">
|
||||
{%= data[i][__("Customer LPO")] %}</td>
|
||||
{% } %}
|
||||
<td style="text-align: right">{%= frappe.datetime.str_to_user(data[i][__("PDC/LC Date")]) %}</td>
|
||||
<td style="text-align: right">{%= data[i][("pdc/lc_ref")] %}</td>
|
||||
<td style="text-align: right">{%= format_currency(data[i][("pdc/lc_amount")], data[i]["currency"]) %}</td>
|
||||
<td style="text-align: right">{%= format_currency(data[i][("remaining_balance")], data[i]["currency"]) %}</td>
|
||||
|
||||
@@ -102,14 +102,19 @@ frappe.query_reports["Accounts Receivable"] = {
|
||||
"fieldtype": "Link",
|
||||
"options": "Sales Person"
|
||||
},
|
||||
{
|
||||
"fieldname":"based_on_payment_terms",
|
||||
"label": __("Based On Payment Terms"),
|
||||
"fieldtype": "Check",
|
||||
},
|
||||
{
|
||||
"fieldname":"show_pdc_in_print",
|
||||
"label": __("Show PDC in Print"),
|
||||
"fieldtype": "Check",
|
||||
},
|
||||
{
|
||||
"fieldname":"based_on_payment_terms",
|
||||
"label": __("Based On Payment Terms"),
|
||||
"fieldname":"show_sales_person_in_print",
|
||||
"label": __("Show Sales Person in Print"),
|
||||
"fieldtype": "Check",
|
||||
},
|
||||
{
|
||||
|
||||
@@ -194,10 +194,9 @@ class ReceivablePayableReport(object):
|
||||
self.payment_term_map = self.get_payment_term_detail(voucher_nos)
|
||||
|
||||
for gle in gl_entries_data:
|
||||
if self.is_receivable_or_payable(gle, self.dr_or_cr, future_vouchers):
|
||||
if self.is_receivable_or_payable(gle, self.dr_or_cr, future_vouchers, return_entries):
|
||||
outstanding_amount, credit_note_amount, payment_amount = self.get_outstanding_amount(
|
||||
gle,self.filters.report_date, self.dr_or_cr, return_entries)
|
||||
|
||||
temp_outstanding_amt = outstanding_amount
|
||||
temp_credit_note_amt = credit_note_amount
|
||||
|
||||
@@ -377,7 +376,7 @@ class ReceivablePayableReport(object):
|
||||
# returns a generator
|
||||
return self.get_gl_entries(party_type, report_date)
|
||||
|
||||
def is_receivable_or_payable(self, gle, dr_or_cr, future_vouchers):
|
||||
def is_receivable_or_payable(self, gle, dr_or_cr, future_vouchers, return_entries):
|
||||
return (
|
||||
# advance
|
||||
(not gle.against_voucher) or
|
||||
@@ -388,30 +387,37 @@ class ReceivablePayableReport(object):
|
||||
# sales invoice/purchase invoice
|
||||
(gle.against_voucher==gle.voucher_no and gle.get(dr_or_cr) > 0) or
|
||||
|
||||
# standalone credit notes
|
||||
(gle.against_voucher==gle.voucher_no and gle.voucher_no in return_entries and not return_entries.get(gle.voucher_no)) or
|
||||
|
||||
# entries adjusted with future vouchers
|
||||
((gle.against_voucher_type, gle.against_voucher) in future_vouchers)
|
||||
)
|
||||
|
||||
def get_return_entries(self, party_type):
|
||||
doctype = "Sales Invoice" if party_type=="Customer" else "Purchase Invoice"
|
||||
return [d.name for d in frappe.get_all(doctype, filters={"is_return": 1, "docstatus": 1})]
|
||||
return_entries = frappe._dict(frappe.get_all(doctype,
|
||||
filters={"is_return": 1, "docstatus": 1}, fields=["name", "return_against"], as_list=1))
|
||||
return return_entries
|
||||
|
||||
def get_outstanding_amount(self, gle, report_date, dr_or_cr, return_entries):
|
||||
payment_amount, credit_note_amount = 0.0, 0.0
|
||||
reverse_dr_or_cr = "credit" if dr_or_cr=="debit" else "debit"
|
||||
|
||||
for e in self.get_gl_entries_for(gle.party, gle.party_type, gle.voucher_type, gle.voucher_no):
|
||||
if getdate(e.posting_date) <= report_date and e.name!=gle.name:
|
||||
if getdate(e.posting_date) <= report_date \
|
||||
and (e.name!=gle.name or (e.voucher_no in return_entries and not return_entries.get(e.voucher_no))):
|
||||
|
||||
amount = flt(e.get(reverse_dr_or_cr), self.currency_precision) - flt(e.get(dr_or_cr), self.currency_precision)
|
||||
if e.voucher_no not in return_entries:
|
||||
payment_amount += amount
|
||||
else:
|
||||
credit_note_amount += amount
|
||||
|
||||
outstanding_amount = (flt((flt(gle.get(dr_or_cr), self.currency_precision)
|
||||
- flt(gle.get(reverse_dr_or_cr), self.currency_precision)
|
||||
- payment_amount - credit_note_amount), self.currency_precision))
|
||||
voucher_amount = flt(gle.get(dr_or_cr), self.currency_precision) - flt(gle.get(reverse_dr_or_cr), self.currency_precision)
|
||||
if gle.voucher_no in return_entries and not return_entries.get(gle.voucher_no):
|
||||
voucher_amount = 0
|
||||
|
||||
outstanding_amount = flt((voucher_amount - payment_amount - credit_note_amount), self.currency_precision)
|
||||
credit_note_amount = flt(credit_note_amount, self.currency_precision)
|
||||
|
||||
return outstanding_amount, credit_note_amount, payment_amount
|
||||
|
||||
@@ -136,7 +136,8 @@ class AccountsReceivableSummary(ReceivablePayableReport):
|
||||
|
||||
partywise_total = self.get_partywise_total(party_naming_by, args)
|
||||
|
||||
partywise_advance_amount = get_partywise_advanced_payment_amount(args.get("party_type")) or {}
|
||||
partywise_advance_amount = get_partywise_advanced_payment_amount(args.get("party_type"),
|
||||
self.filters.get("report_date")) or {}
|
||||
for party, party_dict in iteritems(partywise_total):
|
||||
row = [party]
|
||||
|
||||
@@ -145,8 +146,12 @@ class AccountsReceivableSummary(ReceivablePayableReport):
|
||||
|
||||
row += [partywise_advance_amount.get(party, 0)]
|
||||
|
||||
paid_amt = 0
|
||||
if party_dict.paid_amt > 0:
|
||||
paid_amt = flt(party_dict.paid_amt - partywise_advance_amount.get(party, 0))
|
||||
|
||||
row += [
|
||||
party_dict.invoiced_amt, party_dict.paid_amt, party_dict.credit_amt, party_dict.outstanding_amt,
|
||||
party_dict.invoiced_amt, paid_amt, party_dict.credit_amt, party_dict.outstanding_amt,
|
||||
party_dict.range1, party_dict.range2, party_dict.range3, party_dict.range4,
|
||||
]
|
||||
|
||||
@@ -205,7 +210,7 @@ class AccountsReceivableSummary(ReceivablePayableReport):
|
||||
|
||||
cols += ["invoiced_amt", "paid_amt", "credit_amt",
|
||||
"outstanding_amt", "age", "range1", "range2", "range3", "range4", "currency", "pdc/lc_date", "pdc/lc_ref",
|
||||
"pdc/lc_amount", "remaining_balance"]
|
||||
"pdc/lc_amount"]
|
||||
|
||||
if args.get("party_type") == "Supplier":
|
||||
cols += ["supplier_group", "remarks"]
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
from __future__ import unicode_literals
|
||||
import frappe
|
||||
import erpnext
|
||||
from frappe import _
|
||||
from frappe import _, scrub
|
||||
from frappe.utils import getdate, nowdate
|
||||
from six import iteritems, itervalues
|
||||
|
||||
@@ -14,6 +14,9 @@ class PartyLedgerSummaryReport(object):
|
||||
self.filters.from_date = getdate(self.filters.from_date or nowdate())
|
||||
self.filters.to_date = getdate(self.filters.to_date or nowdate())
|
||||
|
||||
if not self.filters.get("company"):
|
||||
self.filters["company"] = frappe.db.get_single_value('Global Defaults', 'default_company')
|
||||
|
||||
def run(self, args):
|
||||
if self.filters.from_date > self.filters.to_date:
|
||||
frappe.throw(_("From Date must be before To Date"))
|
||||
@@ -21,10 +24,9 @@ class PartyLedgerSummaryReport(object):
|
||||
self.filters.party_type = args.get("party_type")
|
||||
self.party_naming_by = frappe.db.get_value(args.get("naming_by")[0], None, args.get("naming_by")[1])
|
||||
|
||||
discount_account_field = "discount_allowed_account" if self.filters.party_type == "Customer" \
|
||||
else "discount_received_account"
|
||||
self.round_off_account, self.write_off_account, self.discount_account = frappe.get_cached_value('Company',
|
||||
self.filters.company, ["round_off_account", "write_off_account", discount_account_field])
|
||||
self.get_gl_entries()
|
||||
self.get_return_invoices()
|
||||
self.get_party_adjustment_amounts()
|
||||
|
||||
columns = self.get_columns()
|
||||
data = self.get_data()
|
||||
@@ -48,7 +50,6 @@ class PartyLedgerSummaryReport(object):
|
||||
})
|
||||
|
||||
credit_or_debit_note = "Credit Note" if self.filters.party_type == "Customer" else "Debit Note"
|
||||
discount_allowed_or_received = "Discount Allowed" if self.filters.party_type == "Customer" else "Discount Received"
|
||||
|
||||
columns += [
|
||||
{
|
||||
@@ -79,27 +80,19 @@ class PartyLedgerSummaryReport(object):
|
||||
"options": "currency",
|
||||
"width": 120
|
||||
},
|
||||
{
|
||||
"label": _(discount_allowed_or_received),
|
||||
"fieldname": "discount_amount",
|
||||
]
|
||||
|
||||
for account in self.party_adjustment_accounts:
|
||||
columns.append({
|
||||
"label": account,
|
||||
"fieldname": "adj_" + scrub(account),
|
||||
"fieldtype": "Currency",
|
||||
"options": "currency",
|
||||
"width": 120
|
||||
},
|
||||
{
|
||||
"label": _("Write Off Amount"),
|
||||
"fieldname": "write_off_amount",
|
||||
"fieldtype": "Currency",
|
||||
"options": "currency",
|
||||
"width": 120
|
||||
},
|
||||
{
|
||||
"label": _("Other Adjustments"),
|
||||
"fieldname": "adjustment_amount",
|
||||
"fieldtype": "Currency",
|
||||
"options": "currency",
|
||||
"width": 120
|
||||
},
|
||||
"width": 120,
|
||||
"is_adjustment": 1
|
||||
})
|
||||
|
||||
columns += [
|
||||
{
|
||||
"label": _("Closing Balance"),
|
||||
"fieldname": "closing_balance",
|
||||
@@ -119,17 +112,10 @@ class PartyLedgerSummaryReport(object):
|
||||
return columns
|
||||
|
||||
def get_data(self):
|
||||
if not self.filters.get("company"):
|
||||
self.filters["company"] = frappe.db.get_single_value('Global Defaults', 'default_company')
|
||||
|
||||
company_currency = frappe.get_cached_value('Company', self.filters.get("company"), "default_currency")
|
||||
invoice_dr_or_cr = "debit" if self.filters.party_type == "Customer" else "credit"
|
||||
reverse_dr_or_cr = "credit" if self.filters.party_type == "Customer" else "debit"
|
||||
|
||||
self.get_gl_entries()
|
||||
self.get_return_invoices()
|
||||
self.get_party_adjustment_amounts()
|
||||
|
||||
self.party_data = frappe._dict({})
|
||||
for gle in self.gl_entries:
|
||||
self.party_data.setdefault(gle.party, frappe._dict({
|
||||
@@ -146,7 +132,7 @@ class PartyLedgerSummaryReport(object):
|
||||
amount = gle.get(invoice_dr_or_cr) - gle.get(reverse_dr_or_cr)
|
||||
self.party_data[gle.party].closing_balance += amount
|
||||
|
||||
if gle.posting_date < self.filters.from_date:
|
||||
if gle.posting_date < self.filters.from_date or gle.is_opening == "Yes":
|
||||
self.party_data[gle.party].opening_balance += amount
|
||||
else:
|
||||
if amount > 0:
|
||||
@@ -161,9 +147,10 @@ class PartyLedgerSummaryReport(object):
|
||||
if row.opening_balance or row.invoiced_amount or row.paid_amount or row.return_amount or row.closing_amount:
|
||||
total_party_adjustment = sum([amount for amount in itervalues(self.party_adjustment_details.get(party, {}))])
|
||||
row.paid_amount -= total_party_adjustment
|
||||
row.discount_amount = self.party_adjustment_details.get(party, {}).get(self.discount_account, 0)
|
||||
row.write_off_amount = self.party_adjustment_details.get(party, {}).get(self.write_off_account, 0)
|
||||
row.adjustment_amount = total_party_adjustment - row.discount_amount - row.write_off_amount
|
||||
|
||||
adjustments = self.party_adjustment_details.get(party, {})
|
||||
for account in self.party_adjustment_accounts:
|
||||
row["adj_" + scrub(account)] = adjustments.get(account, 0)
|
||||
|
||||
out.append(row)
|
||||
|
||||
@@ -182,7 +169,7 @@ class PartyLedgerSummaryReport(object):
|
||||
self.gl_entries = frappe.db.sql("""
|
||||
select
|
||||
gle.posting_date, gle.party, gle.voucher_type, gle.voucher_no, gle.against_voucher_type,
|
||||
gle.against_voucher, gle.debit, gle.credit {join_field}
|
||||
gle.against_voucher, gle.debit, gle.credit, gle.is_opening {join_field}
|
||||
from `tabGL Entry` gle
|
||||
{join}
|
||||
where
|
||||
@@ -254,9 +241,10 @@ class PartyLedgerSummaryReport(object):
|
||||
|
||||
def get_party_adjustment_amounts(self):
|
||||
conditions = self.prepare_conditions()
|
||||
income_or_expense = "Expense" if self.filters.party_type == "Customer" else "Income"
|
||||
income_or_expense = "Expense Account" if self.filters.party_type == "Customer" else "Income Account"
|
||||
invoice_dr_or_cr = "debit" if self.filters.party_type == "Customer" else "credit"
|
||||
reverse_dr_or_cr = "credit" if self.filters.party_type == "Customer" else "debit"
|
||||
round_off_account = frappe.get_cached_value('Company', self.filters.company, "round_off_account")
|
||||
|
||||
gl_entries = frappe.db.sql("""
|
||||
select
|
||||
@@ -267,7 +255,7 @@ class PartyLedgerSummaryReport(object):
|
||||
docstatus < 2
|
||||
and (voucher_type, voucher_no) in (
|
||||
select voucher_type, voucher_no from `tabGL Entry` gle, `tabAccount` acc
|
||||
where acc.name = gle.account and acc.root_type = '{income_or_expense}'
|
||||
where acc.name = gle.account and acc.account_type = '{income_or_expense}'
|
||||
and gle.posting_date between %(from_date)s and %(to_date)s and gle.docstatus < 2
|
||||
) and (voucher_type, voucher_no) in (
|
||||
select voucher_type, voucher_no from `tabGL Entry` gle
|
||||
@@ -277,6 +265,7 @@ class PartyLedgerSummaryReport(object):
|
||||
""".format(conditions=conditions, income_or_expense=income_or_expense), self.filters, as_dict=True)
|
||||
|
||||
self.party_adjustment_details = {}
|
||||
self.party_adjustment_accounts = set()
|
||||
adjustment_voucher_entries = {}
|
||||
for gle in gl_entries:
|
||||
adjustment_voucher_entries.setdefault((gle.voucher_type, gle.voucher_no), [])
|
||||
@@ -288,12 +277,12 @@ class PartyLedgerSummaryReport(object):
|
||||
has_irrelevant_entry = False
|
||||
|
||||
for gle in voucher_gl_entries:
|
||||
if gle.account == self.round_off_account:
|
||||
if gle.account == round_off_account:
|
||||
continue
|
||||
elif gle.party:
|
||||
parties.setdefault(gle.party, 0)
|
||||
parties[gle.party] += gle.get(reverse_dr_or_cr) - gle.get(invoice_dr_or_cr)
|
||||
elif frappe.get_cached_value("Account", gle.account, "root_type") == income_or_expense:
|
||||
elif frappe.get_cached_value("Account", gle.account, "account_type") == income_or_expense:
|
||||
accounts.setdefault(gle.account, 0)
|
||||
accounts[gle.account] += gle.get(invoice_dr_or_cr) - gle.get(reverse_dr_or_cr)
|
||||
else:
|
||||
@@ -303,11 +292,13 @@ class PartyLedgerSummaryReport(object):
|
||||
if len(parties) == 1:
|
||||
party = parties.keys()[0]
|
||||
for account, amount in iteritems(accounts):
|
||||
self.party_adjustment_accounts.add(account)
|
||||
self.party_adjustment_details.setdefault(party, {})
|
||||
self.party_adjustment_details[party].setdefault(account, 0)
|
||||
self.party_adjustment_details[party][account] += amount
|
||||
elif len(accounts) == 1 and not has_irrelevant_entry:
|
||||
account = accounts.keys()[0]
|
||||
self.party_adjustment_accounts.add(account)
|
||||
for party, amount in iteritems(parties):
|
||||
self.party_adjustment_details.setdefault(party, {})
|
||||
self.party_adjustment_details[party].setdefault(account, 0)
|
||||
|
||||
@@ -54,8 +54,10 @@ def _execute(filters=None, additional_table_columns=None, additional_query_colum
|
||||
delivery_note, d.income_account, d.cost_center, d.stock_qty, d.stock_uom
|
||||
]
|
||||
|
||||
row += [(d.base_net_rate * d.qty)/d.stock_qty, d.base_net_amount] \
|
||||
if d.stock_uom != d.uom and d.stock_qty != 0 else [d.base_net_rate, d.base_net_amount]
|
||||
if d.stock_uom != d.uom and d.stock_qty:
|
||||
row += [(d.base_net_rate * d.qty)/d.stock_qty, d.base_net_amount]
|
||||
else:
|
||||
row += [d.base_net_rate, d.base_net_amount]
|
||||
|
||||
total_tax = 0
|
||||
for tax in tax_columns:
|
||||
@@ -108,13 +110,13 @@ def get_conditions(filters):
|
||||
conditions += """ and exists(select name from `tabSales Invoice Payment`
|
||||
where parent=`tabSales Invoice`.name
|
||||
and ifnull(`tabSales Invoice Payment`.mode_of_payment, '') = %(mode_of_payment)s)"""
|
||||
|
||||
|
||||
if filters.get("warehouse"):
|
||||
conditions += """ and exists(select name from `tabSales Invoice Item`
|
||||
where parent=`tabSales Invoice`.name
|
||||
and ifnull(`tabSales Invoice Item`.warehouse, '') = %(warehouse)s)"""
|
||||
|
||||
|
||||
|
||||
if filters.get("brand"):
|
||||
conditions += """ and exists(select name from `tabSales Invoice Item`
|
||||
where parent=`tabSales Invoice`.name
|
||||
@@ -131,10 +133,10 @@ def get_conditions(filters):
|
||||
def get_items(filters, additional_query_columns):
|
||||
conditions = get_conditions(filters)
|
||||
match_conditions = frappe.build_match_conditions("Sales Invoice")
|
||||
|
||||
|
||||
if match_conditions:
|
||||
match_conditions = " and {0} ".format(match_conditions)
|
||||
|
||||
|
||||
if additional_query_columns:
|
||||
additional_query_columns = ', ' + ', '.join(additional_query_columns)
|
||||
|
||||
|
||||
@@ -133,6 +133,13 @@ def get_columns(filters):
|
||||
"options": filters.get("based_on"),
|
||||
"width": 300
|
||||
},
|
||||
{
|
||||
"fieldname": "currency",
|
||||
"label": _("Currency"),
|
||||
"fieldtype": "Link",
|
||||
"options": "Currency",
|
||||
"hidden": 1
|
||||
},
|
||||
{
|
||||
"fieldname": "income",
|
||||
"label": _("Income"),
|
||||
@@ -153,13 +160,6 @@ def get_columns(filters):
|
||||
"fieldtype": "Currency",
|
||||
"options": "currency",
|
||||
"width": 120
|
||||
},
|
||||
{
|
||||
"fieldname": "currency",
|
||||
"label": _("Currency"),
|
||||
"fieldtype": "Link",
|
||||
"options": "Currency",
|
||||
"hidden": 1
|
||||
}
|
||||
]
|
||||
|
||||
@@ -191,4 +191,4 @@ def set_gl_entries_by_account(company, from_date, to_date, based_on, gl_entries_
|
||||
for entry in gl_entries:
|
||||
gl_entries_by_account.setdefault(entry.based_on, []).append(entry)
|
||||
|
||||
return gl_entries_by_account
|
||||
return gl_entries_by_account
|
||||
|
||||
@@ -66,8 +66,8 @@ def _execute(filters=None, additional_table_columns=None, additional_query_colum
|
||||
total_tax += tax_amount
|
||||
row.append(tax_amount)
|
||||
|
||||
# total tax, grand total, outstanding amount & rounded total
|
||||
row += [total_tax, inv.base_grand_total, flt(inv.base_grand_total, 2), inv.outstanding_amount]
|
||||
# total tax, grand total, rounded total & outstanding amount
|
||||
row += [total_tax, inv.base_grand_total, flt(inv.base_grand_total, 0), inv.outstanding_amount]
|
||||
data.append(row)
|
||||
|
||||
return columns, data
|
||||
|
||||
@@ -55,12 +55,15 @@ def get_result(filters):
|
||||
supplier = supplier_map[d]
|
||||
|
||||
tds_doc = tds_docs[supplier.tax_withholding_category]
|
||||
account = [i.account for i in tds_doc.accounts if i.company == filters.company][0]
|
||||
account_list = [i.account for i in tds_doc.accounts if i.company == filters.company]
|
||||
|
||||
if account_list:
|
||||
account = account_list[0]
|
||||
|
||||
for k in gle_map[d]:
|
||||
if k.party == supplier_map[d] and k.credit > 0:
|
||||
total_amount_credited += k.credit
|
||||
elif k.account == account and k.credit > 0:
|
||||
elif account_list and k.account == account and k.credit > 0:
|
||||
tds_deducted = k.credit
|
||||
total_amount_credited += k.credit
|
||||
|
||||
|
||||
@@ -544,14 +544,14 @@ def fix_total_debit_credit():
|
||||
(dr_or_cr, dr_or_cr, '%s', '%s', '%s', dr_or_cr),
|
||||
(d.diff, d.voucher_type, d.voucher_no))
|
||||
|
||||
def get_stock_and_account_difference(account_list=None, posting_date=None):
|
||||
def get_stock_and_account_difference(account_list=None, posting_date=None, company=None):
|
||||
from erpnext.stock.utils import get_stock_value_on
|
||||
from erpnext.stock import get_warehouse_account_map
|
||||
|
||||
if not posting_date: posting_date = nowdate()
|
||||
|
||||
difference = {}
|
||||
warehouse_account = get_warehouse_account_map()
|
||||
warehouse_account = get_warehouse_account_map(company)
|
||||
|
||||
for warehouse, account_data in iteritems(warehouse_account):
|
||||
if account_data.get('account') in account_list:
|
||||
@@ -615,7 +615,7 @@ def get_held_invoices(party_type, party):
|
||||
return held_invoices
|
||||
|
||||
|
||||
def get_outstanding_invoices(party_type, party, account, condition=None, limit=None):
|
||||
def get_outstanding_invoices(party_type, party, account, condition=None):
|
||||
outstanding_invoices = []
|
||||
precision = frappe.get_precision("Sales Invoice", "outstanding_amount") or 2
|
||||
|
||||
@@ -628,7 +628,6 @@ def get_outstanding_invoices(party_type, party, account, condition=None, limit=N
|
||||
|
||||
invoice = 'Sales Invoice' if erpnext.get_party_account_type(party_type) == 'Receivable' else 'Purchase Invoice'
|
||||
held_invoices = get_held_invoices(party_type, party)
|
||||
limit_cond = "limit %s" % limit if limit else ""
|
||||
|
||||
invoice_list = frappe.db.sql("""
|
||||
select
|
||||
@@ -643,11 +642,10 @@ def get_outstanding_invoices(party_type, party, account, condition=None, limit=N
|
||||
and (against_voucher = '' or against_voucher is null))
|
||||
or (voucher_type not in ('Journal Entry', 'Payment Entry')))
|
||||
group by voucher_type, voucher_no
|
||||
order by posting_date, name {limit_cond}""".format(
|
||||
order by posting_date, name""".format(
|
||||
dr_or_cr=dr_or_cr,
|
||||
invoice = invoice,
|
||||
condition=condition or "",
|
||||
limit_cond = limit_cond
|
||||
condition=condition or ""
|
||||
), {
|
||||
"party_type": party_type,
|
||||
"party": party,
|
||||
|
||||
Reference in New Issue
Block a user