Fixed merge conflict

This commit is contained in:
Nabin Hait
2019-04-15 11:41:54 +05:30
116 changed files with 9879 additions and 8255 deletions

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -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",
},
{

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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