[feature] Opening Invoice Creation Tool (#11589)
* [enhance] Opening Invoice Tool create Opening Sales/Purchase Invoices * [minor] added progress bar while creating invoice * [minor] allow bulk upload for the invoices * [minor] calculate item rate from net total * [minor] added defaults for invoices fields, create gl entries only if grand_total is greater than 0 * [minor] check mandatory values before making opening invoices * [minor] enable primary button if there is any error while creating invoices * [minor] minor fixes, set company currency as invoice currency added tests * [dashboard] added Opening Invoice Summery section in Dashboard * [minor] added total invoices count on dashboard * [minor] don't show dashboard if there are no opening invoices available * [minor] added Opening Invoice Tools to Account's Tools section * [minor] codecy fixes * [fix] refactored general ledger and buttons on charts * [fix] tests
This commit is contained in:
parent
78ab8235f6
commit
d3f5d0961a
@ -41,6 +41,41 @@ frappe.treeview_settings["Account"] = {
|
||||
description: __("Optional. Sets company's default currency, if not specified.")}
|
||||
],
|
||||
ignore_fields:["parent_account"],
|
||||
onload: function(treeview) {
|
||||
function get_company() {
|
||||
return treeview.page.fields_dict.company.get_value();
|
||||
}
|
||||
|
||||
// tools
|
||||
treeview.page.add_inner_button(__("Chart of Cost Centers"), function() {
|
||||
frappe.set_route('Tree', 'Cost Center', {company: get_company()});
|
||||
}, __('View'));
|
||||
|
||||
treeview.page.add_inner_button(__("Opening Invoice Creation Tool"), function() {
|
||||
frappe.set_route('Form', 'Opening Invoice Creation Tool', {company: get_company()});
|
||||
}, __('View'));
|
||||
|
||||
treeview.page.add_inner_button(__("Period Closing Voucher"), function() {
|
||||
frappe.set_route('List', 'Period Closing Voucher', {company: get_company()});
|
||||
}, __('View'));
|
||||
|
||||
// make
|
||||
treeview.page.add_inner_button(__("Journal Entry"), function() {
|
||||
frappe.new_doc('Journal Entry', {company: get_company()});
|
||||
}, __('Make'));
|
||||
treeview.page.add_inner_button(__("New Company"), function() {
|
||||
frappe.new_doc('Company');
|
||||
}, __('Make'));
|
||||
|
||||
// financial statements
|
||||
for (let report of ['Trial Balance', 'General Ledger', 'Balance Sheet',
|
||||
'Profit and Loss', 'Cash Flow Statement', 'Accounts Payable', 'Accounts Receivable']) {
|
||||
treeview.page.add_inner_button(__(report), function() {
|
||||
frappe.set_route('query-report', report, {company: get_company()});
|
||||
}, __('Financial Statements'));
|
||||
}
|
||||
|
||||
},
|
||||
onrender: function(node) {
|
||||
var dr_or_cr = node.data.balance < 0 ? "Cr" : "Dr";
|
||||
if (node.data && node.data.balance!==undefined) {
|
||||
|
@ -23,5 +23,30 @@ frappe.treeview_settings["Cost Center"] = {
|
||||
{fieldtype:'Check', fieldname:'is_group', label:__('Is Group'),
|
||||
description:__('Further cost centers can be made under Groups but entries can be made against non-Groups')}
|
||||
],
|
||||
ignore_fields:["parent_cost_center"]
|
||||
ignore_fields:["parent_cost_center"],
|
||||
onload: function(treeview) {
|
||||
function get_company() {
|
||||
return treeview.page.fields_dict.company.get_value();
|
||||
}
|
||||
|
||||
// tools
|
||||
treeview.page.add_inner_button(__("Chart of Accounts"), function() {
|
||||
frappe.set_route('Tree', 'Account', {company: get_company()});
|
||||
}, __('View'));
|
||||
|
||||
// make
|
||||
treeview.page.add_inner_button(__("Budget List"), function() {
|
||||
frappe.set_route('List', 'Budget', {company: get_company()});
|
||||
}, __('Budget'));
|
||||
|
||||
treeview.page.add_inner_button(__("Monthly Distribution"), function() {
|
||||
frappe.set_route('List', 'Monthly Distribution', {company: get_company()});
|
||||
}, __('Budget'));
|
||||
|
||||
treeview.page.add_inner_button(__("Budget Variance Report"), function() {
|
||||
frappe.set_route('query-report', 'Budget Variance Report', {company: get_company()});
|
||||
}, __('Budget'));
|
||||
|
||||
},
|
||||
|
||||
}
|
@ -0,0 +1,96 @@
|
||||
// Copyright (c) 2017, Frappe Technologies Pvt. Ltd. and contributors
|
||||
// For license information, please see license.txt
|
||||
|
||||
frappe.ui.form.on('Opening Invoice Creation Tool', {
|
||||
setup: function(frm) {
|
||||
frm.set_query('party_type', 'invoices', function(doc, cdt, cdn) {
|
||||
return {
|
||||
filters: {
|
||||
'name': ['in', 'Customer,Supplier']
|
||||
}
|
||||
};
|
||||
});
|
||||
},
|
||||
|
||||
refresh: function(frm) {
|
||||
frm.disable_save();
|
||||
frm.trigger("make_dashboard");
|
||||
frm.page.set_primary_action(__("Make Invoices"), () => {
|
||||
let btn_primary = frm.page.btn_primary.get(0);
|
||||
return frm.call({
|
||||
doc: frm.doc,
|
||||
freeze: true,
|
||||
btn: $(btn_primary),
|
||||
method: "make_invoices",
|
||||
freeze_message: __("Creating {0} Invoice", [frm.doc.invoice_type]),
|
||||
callback: (r) => {
|
||||
if(!r.exc){
|
||||
frappe.msgprint(__("Opening {0} Invoice created", [frm.doc.invoice_type]));
|
||||
frm.clear_table("invoices");
|
||||
frm.refresh_fields();
|
||||
frm.reload_doc();
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
},
|
||||
|
||||
company: function(frm) {
|
||||
frappe.call({
|
||||
method: 'erpnext.accounts.doctype.opening_invoice_creation_tool.opening_invoice_creation_tool.get_temporary_opening_account',
|
||||
args: {
|
||||
company: frm.doc.company
|
||||
},
|
||||
callback: (r) => {
|
||||
if (r.message) {
|
||||
frm.doc.__onload.temporary_opening_account = r.message;
|
||||
frm.trigger('update_invoice_table');
|
||||
}
|
||||
}
|
||||
})
|
||||
},
|
||||
|
||||
invoice_type: function(frm) {
|
||||
$.each(frm.doc.invoices, (idx, row) => {
|
||||
row.party_type = frm.doc.invoice_type == "Sales"? "Customer": "Supplier";
|
||||
row.party = "";
|
||||
});
|
||||
frm.refresh_fields();
|
||||
},
|
||||
|
||||
make_dashboard: function(frm) {
|
||||
let max_count = frm.doc.__onload.max_count;
|
||||
let opening_invoices_summary = frm.doc.__onload.opening_invoices_summary;
|
||||
if(!$.isEmptyObject(opening_invoices_summary)) {
|
||||
let section = frm.dashboard.add_section(
|
||||
frappe.render_template('opening_invoice_creation_tool_dashboard', {
|
||||
data: opening_invoices_summary,
|
||||
max_count: max_count
|
||||
})
|
||||
);
|
||||
|
||||
section.on('click', '.invoice-link', function() {
|
||||
let doctype = $(this).attr('data-type');
|
||||
let company = $(this).attr('data-company');
|
||||
frappe.set_route('List', doctype,
|
||||
{'is_opening': 'Yes', 'company': company, 'docstatus': 1});
|
||||
});
|
||||
frm.dashboard.show();
|
||||
}
|
||||
},
|
||||
|
||||
update_invoice_table: function(frm) {
|
||||
$.each(frm.doc.invoices, (idx, row) => {
|
||||
if (!row.temporary_opening_account) {
|
||||
row.temporary_opening_account = frm.doc.__onload.temporary_opening_account;
|
||||
}
|
||||
row.party_type = frm.doc.invoice_type == "Sales"? "Customer": "Supplier";
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
frappe.ui.form.on('Opening Invoice Creation Tool Item', {
|
||||
invoices_add: (frm) => {
|
||||
frm.trigger('update_invoice_table');
|
||||
}
|
||||
});
|
@ -0,0 +1,184 @@
|
||||
{
|
||||
"allow_copy": 1,
|
||||
"allow_guest_to_view": 0,
|
||||
"allow_import": 0,
|
||||
"allow_rename": 0,
|
||||
"beta": 1,
|
||||
"creation": "2017-08-29 02:22:54.947711",
|
||||
"custom": 0,
|
||||
"docstatus": 0,
|
||||
"doctype": "DocType",
|
||||
"document_type": "",
|
||||
"editable_grid": 1,
|
||||
"engine": "InnoDB",
|
||||
"fields": [
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fieldname": "company",
|
||||
"fieldtype": "Link",
|
||||
"hidden": 0,
|
||||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_global_search": 0,
|
||||
"in_list_view": 1,
|
||||
"in_standard_filter": 0,
|
||||
"label": "Company",
|
||||
"length": 0,
|
||||
"no_copy": 0,
|
||||
"options": "Company",
|
||||
"permlevel": 0,
|
||||
"precision": "",
|
||||
"print_hide": 0,
|
||||
"print_hide_if_no_value": 0,
|
||||
"read_only": 0,
|
||||
"remember_last_selected_value": 0,
|
||||
"report_hide": 0,
|
||||
"reqd": 1,
|
||||
"search_index": 0,
|
||||
"set_only_once": 0,
|
||||
"unique": 0
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fieldname": "invoice_type",
|
||||
"fieldtype": "Select",
|
||||
"hidden": 0,
|
||||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_global_search": 0,
|
||||
"in_list_view": 1,
|
||||
"in_standard_filter": 0,
|
||||
"label": "Invoice Type",
|
||||
"length": 0,
|
||||
"no_copy": 0,
|
||||
"options": "Sales\nPurchase",
|
||||
"permlevel": 0,
|
||||
"precision": "",
|
||||
"print_hide": 0,
|
||||
"print_hide_if_no_value": 0,
|
||||
"read_only": 0,
|
||||
"remember_last_selected_value": 0,
|
||||
"report_hide": 0,
|
||||
"reqd": 1,
|
||||
"search_index": 0,
|
||||
"set_only_once": 0,
|
||||
"unique": 0
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fieldname": "section_break_4",
|
||||
"fieldtype": "Section Break",
|
||||
"hidden": 0,
|
||||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_global_search": 0,
|
||||
"in_list_view": 0,
|
||||
"in_standard_filter": 0,
|
||||
"label": "Invoices",
|
||||
"length": 0,
|
||||
"no_copy": 0,
|
||||
"permlevel": 0,
|
||||
"precision": "",
|
||||
"print_hide": 0,
|
||||
"print_hide_if_no_value": 0,
|
||||
"read_only": 0,
|
||||
"remember_last_selected_value": 0,
|
||||
"report_hide": 0,
|
||||
"reqd": 0,
|
||||
"search_index": 0,
|
||||
"set_only_once": 0,
|
||||
"unique": 0
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 1,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fieldname": "invoices",
|
||||
"fieldtype": "Table",
|
||||
"hidden": 0,
|
||||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_global_search": 0,
|
||||
"in_list_view": 0,
|
||||
"in_standard_filter": 0,
|
||||
"length": 0,
|
||||
"no_copy": 0,
|
||||
"options": "Opening Invoice Creation Tool Item",
|
||||
"permlevel": 0,
|
||||
"precision": "",
|
||||
"print_hide": 0,
|
||||
"print_hide_if_no_value": 0,
|
||||
"read_only": 0,
|
||||
"remember_last_selected_value": 0,
|
||||
"report_hide": 0,
|
||||
"reqd": 1,
|
||||
"search_index": 0,
|
||||
"set_only_once": 0,
|
||||
"unique": 0
|
||||
}
|
||||
],
|
||||
"has_web_view": 0,
|
||||
"hide_heading": 0,
|
||||
"hide_toolbar": 1,
|
||||
"idx": 0,
|
||||
"image_view": 0,
|
||||
"in_create": 0,
|
||||
"is_submittable": 0,
|
||||
"issingle": 1,
|
||||
"istable": 0,
|
||||
"max_attachments": 0,
|
||||
"modified": "2017-09-05 01:30:33.235664",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Accounts",
|
||||
"name": "Opening Invoice Creation Tool",
|
||||
"name_case": "",
|
||||
"owner": "Administrator",
|
||||
"permissions": [
|
||||
{
|
||||
"amend": 0,
|
||||
"apply_user_permissions": 0,
|
||||
"cancel": 0,
|
||||
"create": 1,
|
||||
"delete": 0,
|
||||
"email": 1,
|
||||
"export": 0,
|
||||
"if_owner": 0,
|
||||
"import": 0,
|
||||
"permlevel": 0,
|
||||
"print": 1,
|
||||
"read": 1,
|
||||
"report": 0,
|
||||
"role": "System Manager",
|
||||
"set_user_permissions": 0,
|
||||
"share": 1,
|
||||
"submit": 0,
|
||||
"write": 1
|
||||
}
|
||||
],
|
||||
"quick_entry": 1,
|
||||
"read_only": 0,
|
||||
"read_only_onload": 0,
|
||||
"show_name_in_global_search": 0,
|
||||
"sort_field": "modified",
|
||||
"sort_order": "DESC",
|
||||
"track_changes": 1,
|
||||
"track_seen": 0
|
||||
}
|
@ -0,0 +1,163 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# Copyright (c) 2017, Frappe Technologies Pvt. Ltd. and contributors
|
||||
# For license information, please see license.txt
|
||||
|
||||
from __future__ import unicode_literals
|
||||
import frappe
|
||||
from frappe import _
|
||||
from frappe.utils import flt
|
||||
from frappe.model.document import Document
|
||||
|
||||
class OpeningInvoiceCreationTool(Document):
|
||||
def onload(self):
|
||||
"""Load the Opening Invoice summary"""
|
||||
summary, max_count = self.get_opening_invoice_summary()
|
||||
self.set_onload('opening_invoices_summary', summary)
|
||||
self.set_onload('max_count', max_count)
|
||||
self.set_onload('temporary_opening_account', get_temporary_opening_account(self.company))
|
||||
|
||||
def get_opening_invoice_summary(self):
|
||||
def prepare_invoice_summary(doctype, invoices):
|
||||
# add company wise sales / purchase invoice summary
|
||||
paid_amount = []
|
||||
outstanding_amount = []
|
||||
for invoice in invoices:
|
||||
company = invoice.pop("company")
|
||||
_summary = invoices_summary.get(company, {})
|
||||
_summary.update({
|
||||
"currency": company_wise_currency.get(company),
|
||||
doctype: invoice
|
||||
})
|
||||
invoices_summary.update({company: _summary})
|
||||
|
||||
paid_amount.append(invoice.paid_amount)
|
||||
outstanding_amount.append(invoice.outstanding_amount)
|
||||
|
||||
if paid_amount or outstanding_amount:
|
||||
max_count.update({
|
||||
doctype: {
|
||||
"max_paid": max(paid_amount) if paid_amount else 0.0,
|
||||
"max_due": max(outstanding_amount) if outstanding_amount else 0.0
|
||||
}
|
||||
})
|
||||
|
||||
invoices_summary = {}
|
||||
max_count = {}
|
||||
fields = [
|
||||
"company", "count(name) as total_invoices", "sum(outstanding_amount) as outstanding_amount"
|
||||
]
|
||||
companies = frappe.get_all("Company", fields=["name as company", "default_currency as currency"])
|
||||
if not companies:
|
||||
return None, None
|
||||
|
||||
company_wise_currency = {row.company: row.currency for row in companies}
|
||||
for doctype in ["Sales Invoice", "Purchase Invoice"]:
|
||||
invoices = frappe.get_all(doctype, filters=dict(is_opening="Yes", docstatus=1),
|
||||
fields=fields, group_by="company")
|
||||
prepare_invoice_summary(doctype, invoices)
|
||||
|
||||
return invoices_summary, max_count
|
||||
|
||||
def make_invoices(self):
|
||||
names = []
|
||||
mandatory_error_msg = _("Row {idx}: {field} is required to create the Opening {invoice_type} Invoices")
|
||||
if not self.company:
|
||||
frappe.throw(_("Please select the Company"))
|
||||
|
||||
for row in self.invoices:
|
||||
if not row.qty:
|
||||
row.qty = 1.0
|
||||
if not row.party:
|
||||
frappe.throw(mandatory_error_msg.format(
|
||||
idx=row.idx,
|
||||
field= _("Party"),
|
||||
invoice_type=self.invoice_type
|
||||
))
|
||||
# set party type if not available
|
||||
if not row.party_type:
|
||||
row.party_type = "Customer" if self.invoice_type == "Sales" else "Supplier"
|
||||
|
||||
if not row.posting_date:
|
||||
frappe.throw(mandatory_error_msg.format(
|
||||
idx=row.idx,
|
||||
field= _("Party"),
|
||||
invoice_type=self.invoice_type
|
||||
))
|
||||
|
||||
if not row.outstanding_amount:
|
||||
frappe.throw(mandatory_error_msg.format(
|
||||
idx=row.idx,
|
||||
field= _("Outstanding Amount"),
|
||||
invoice_type=self.invoice_type
|
||||
))
|
||||
|
||||
args = self.get_invoice_dict(row=row)
|
||||
if not args:
|
||||
continue
|
||||
|
||||
doc = frappe.get_doc(args).insert()
|
||||
doc.submit()
|
||||
names.append(doc.name)
|
||||
|
||||
if(len(self.invoices) > 5):
|
||||
frappe.publish_realtime("progress",
|
||||
dict(progress=[row.idx, len(self.invoices)], title=_('Creating {0}').format(doc.doctype)),
|
||||
user=frappe.session.user)
|
||||
|
||||
return names
|
||||
|
||||
def get_invoice_dict(self, row=None):
|
||||
def get_item_dict():
|
||||
default_uom = frappe.db.get_single_value("Stock Settings", "stock_uom") or _("Nos")
|
||||
cost_center = frappe.db.get_value("Company", self.company, "cost_center")
|
||||
if not cost_center:
|
||||
frappe.throw(_("Please set the Default Cost Center in {0} company").format(frappe.bold(self.company)))
|
||||
rate = flt(row.outstanding_amount) / row.qty
|
||||
|
||||
return frappe._dict({
|
||||
"uom": default_uom,
|
||||
"rate": rate or 0.0,
|
||||
"qty": row.qty,
|
||||
"conversion_factor": 1.0,
|
||||
"item_name": row.item_name or "Opening Invoice Item",
|
||||
"description": row.item_name or "Opening Invoice Item",
|
||||
income_expense_account_field: row.temporary_opening_account,
|
||||
"cost_center": cost_center
|
||||
})
|
||||
|
||||
if not row:
|
||||
return None
|
||||
|
||||
party_type = "Customer"
|
||||
income_expense_account_field = "income_account"
|
||||
if self.invoice_type == "Purchase":
|
||||
party_type = "Supplier"
|
||||
income_expense_account_field = "expense_account"
|
||||
|
||||
item = get_item_dict()
|
||||
return frappe._dict({
|
||||
"items": [item],
|
||||
"is_opening": "Yes",
|
||||
"set_posting_time": 1,
|
||||
"company": self.company,
|
||||
"due_date": row.due_date,
|
||||
"posting_date": row.posting_date,
|
||||
frappe.scrub(party_type): row.party,
|
||||
"doctype": "Sales Invoice" if self.invoice_type == "Sales" \
|
||||
else "Purchase Invoice",
|
||||
"currency": frappe.db.get_value("Company", self.company, "default_currency")
|
||||
})
|
||||
|
||||
@frappe.whitelist()
|
||||
def get_temporary_opening_account(company=None):
|
||||
if not company:
|
||||
return
|
||||
|
||||
accounts = frappe.get_all("Account", filters={
|
||||
'company': company,
|
||||
'account_type': 'Temporary'
|
||||
})
|
||||
if not accounts:
|
||||
frappe.throw(_("Please add a Temporary Opening account in Chart of Accounts"))
|
||||
|
||||
return accounts[0].name
|
@ -0,0 +1,32 @@
|
||||
<h5 style="margin-top: 0px;">{{ __("Opening Invoices Summary") }}</h5>
|
||||
{% $.each(data, (company, summary) => { %}
|
||||
<h6 style="margin: 15px 0px -10px 0px;"><a class="company-link"> {{ company }}</a></h6>
|
||||
|
||||
<table class="table table-bordered small">
|
||||
<thead>
|
||||
<tr>
|
||||
<td style="width: 33%">{{ __("Invoice Type") }}</td>
|
||||
<td style="width: 33%" class="text-right">{{ __("Opening Invoices") }}</td>
|
||||
<td style="width: 33%" class="text-right">{{ __("Total Outstanding") }}</td>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{% $.each(["Sales Invoice", "Purchase Invoice"], (idx, doctype) => { %}
|
||||
{% if summary[doctype] %}
|
||||
<tr>
|
||||
<td>
|
||||
<a class="invoice-link" data-type="{{ doctype }}" data-company="{{ company }}">
|
||||
{{ __(doctype) }}</a>
|
||||
</td>
|
||||
<td class="text-right">
|
||||
{{ summary[doctype].total_invoices }}
|
||||
</td>
|
||||
<td class="text-right">
|
||||
{{ format_currency(summary[doctype].outstanding_amount, summary.currency, 2) }}
|
||||
</td>
|
||||
</div>
|
||||
{% endif %}
|
||||
{% }); %}
|
||||
</tbody>
|
||||
</table>
|
||||
{% }); %}
|
@ -0,0 +1,23 @@
|
||||
/* eslint-disable */
|
||||
// rename this file from _test_[name] to test_[name] to activate
|
||||
// and remove above this line
|
||||
|
||||
QUnit.test("test: Opening Invoice Creation Tool", function (assert) {
|
||||
let done = assert.async();
|
||||
|
||||
// number of asserts
|
||||
assert.expect(1);
|
||||
|
||||
frappe.run_serially([
|
||||
// insert a new Opening Invoice Creation Tool
|
||||
() => frappe.tests.make('Opening Invoice Creation Tool', [
|
||||
// values to be set
|
||||
{key: 'value'}
|
||||
]),
|
||||
() => {
|
||||
assert.equal(cur_frm.doc.key, 'value');
|
||||
},
|
||||
() => done()
|
||||
]);
|
||||
|
||||
});
|
@ -0,0 +1,79 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# Copyright (c) 2017, Frappe Technologies Pvt. Ltd. and Contributors
|
||||
# See license.txt
|
||||
from __future__ import unicode_literals
|
||||
|
||||
import frappe
|
||||
import unittest
|
||||
|
||||
test_dependencies = ["Customer", "Supplier"]
|
||||
from erpnext.accounts.doctype.opening_invoice_creation_tool.opening_invoice_creation_tool import get_temporary_opening_account
|
||||
|
||||
class TestOpeningInvoiceCreationTool(unittest.TestCase):
|
||||
def make_invoices(self, invoice_type="Sales"):
|
||||
doc = frappe.get_single("Opening Invoice Creation Tool")
|
||||
args = get_opening_invoice_creation_dict(invoice_type=invoice_type)
|
||||
doc.update(args)
|
||||
return doc.make_invoices()
|
||||
|
||||
def test_opening_sales_invoice_creation(self):
|
||||
invoices = self.make_invoices()
|
||||
|
||||
self.assertEqual(len(invoices), 2)
|
||||
expected_value = {
|
||||
"keys": ["customer", "outstanding_amount", "status"],
|
||||
0: ["_Test Customer", 300, "Overdue"],
|
||||
1: ["_Test Customer 1", 250, "Overdue"],
|
||||
}
|
||||
self.check_expected_values(invoices, expected_value)
|
||||
|
||||
def check_expected_values(self, invoices, expected_value, invoice_type="Sales"):
|
||||
doctype = "Sales Invoice" if invoice_type == "Sales" else "Purchase Invoice"
|
||||
|
||||
for invoice_idx, invoice in enumerate(invoices or []):
|
||||
si = frappe.get_doc(doctype, invoice)
|
||||
for field_idx, field in enumerate(expected_value["keys"]):
|
||||
self.assertEqual(si.get(field, ""), expected_value[invoice_idx][field_idx])
|
||||
|
||||
def test_opening_purchase_invoice_creation(self):
|
||||
invoices = self.make_invoices(invoice_type="Purchase")
|
||||
|
||||
self.assertEqual(len(invoices), 2)
|
||||
expected_value = {
|
||||
"keys": ["supplier", "outstanding_amount", "status"],
|
||||
0: ["_Test Supplier", 300, "Overdue"],
|
||||
1: ["_Test Supplier 1", 250, "Overdue"],
|
||||
}
|
||||
self.check_expected_values(invoices, expected_value, invoice_type="Purchase", )
|
||||
|
||||
def get_opening_invoice_creation_dict(**args):
|
||||
party = "Customer" if args.get("invoice_type", "Sales") == "Sales" else "Supplier"
|
||||
company = args.get("company", "_Test Company")
|
||||
|
||||
invoice_dict = frappe._dict({
|
||||
"company": company,
|
||||
"invoice_type": args.get("invoice_type", "Sales"),
|
||||
"invoices": [
|
||||
{
|
||||
"qty": 1.0,
|
||||
"outstanding_amount": 300,
|
||||
"party": "_Test {0}".format(party),
|
||||
"item_name": "Opening Item",
|
||||
"due_date": "2016-09-10",
|
||||
"posting_date": "2016-09-05",
|
||||
"temporary_opening_account": get_temporary_opening_account(company)
|
||||
},
|
||||
{
|
||||
"qty": 2.0,
|
||||
"outstanding_amount": 250,
|
||||
"party": "_Test {0} 1".format(party),
|
||||
"item_name": "Opening Item",
|
||||
"due_date": "2016-09-10",
|
||||
"posting_date": "2016-09-05",
|
||||
"temporary_opening_account": get_temporary_opening_account(company)
|
||||
}
|
||||
]
|
||||
})
|
||||
|
||||
invoice_dict.update(args)
|
||||
return invoice_dict
|
@ -0,0 +1,318 @@
|
||||
{
|
||||
"allow_copy": 0,
|
||||
"allow_guest_to_view": 0,
|
||||
"allow_import": 0,
|
||||
"allow_rename": 0,
|
||||
"beta": 0,
|
||||
"creation": "2017-08-29 04:26:36.159247",
|
||||
"custom": 0,
|
||||
"docstatus": 0,
|
||||
"doctype": "DocType",
|
||||
"document_type": "",
|
||||
"editable_grid": 1,
|
||||
"engine": "InnoDB",
|
||||
"fields": [
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fieldname": "party_type",
|
||||
"fieldtype": "Link",
|
||||
"hidden": 1,
|
||||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_global_search": 0,
|
||||
"in_list_view": 0,
|
||||
"in_standard_filter": 0,
|
||||
"label": "Party Type",
|
||||
"length": 0,
|
||||
"no_copy": 0,
|
||||
"options": "DocType",
|
||||
"permlevel": 0,
|
||||
"precision": "",
|
||||
"print_hide": 0,
|
||||
"print_hide_if_no_value": 0,
|
||||
"read_only": 1,
|
||||
"remember_last_selected_value": 0,
|
||||
"report_hide": 0,
|
||||
"reqd": 0,
|
||||
"search_index": 0,
|
||||
"set_only_once": 0,
|
||||
"unique": 0
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fieldname": "party",
|
||||
"fieldtype": "Dynamic Link",
|
||||
"hidden": 0,
|
||||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_global_search": 0,
|
||||
"in_list_view": 1,
|
||||
"in_standard_filter": 0,
|
||||
"label": "Party",
|
||||
"length": 0,
|
||||
"no_copy": 0,
|
||||
"options": "party_type",
|
||||
"permlevel": 0,
|
||||
"precision": "",
|
||||
"print_hide": 0,
|
||||
"print_hide_if_no_value": 0,
|
||||
"read_only": 0,
|
||||
"remember_last_selected_value": 0,
|
||||
"report_hide": 0,
|
||||
"reqd": 1,
|
||||
"search_index": 0,
|
||||
"set_only_once": 0,
|
||||
"unique": 0
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fieldname": "temporary_opening_account",
|
||||
"fieldtype": "Link",
|
||||
"hidden": 0,
|
||||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_global_search": 0,
|
||||
"in_list_view": 0,
|
||||
"in_standard_filter": 0,
|
||||
"label": "Temporary Opening Account",
|
||||
"length": 0,
|
||||
"no_copy": 0,
|
||||
"options": "Account",
|
||||
"permlevel": 0,
|
||||
"precision": "",
|
||||
"print_hide": 0,
|
||||
"print_hide_if_no_value": 0,
|
||||
"read_only": 0,
|
||||
"remember_last_selected_value": 0,
|
||||
"report_hide": 0,
|
||||
"reqd": 0,
|
||||
"search_index": 0,
|
||||
"set_only_once": 0,
|
||||
"unique": 0
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fieldname": "column_break_3",
|
||||
"fieldtype": "Column Break",
|
||||
"hidden": 0,
|
||||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_global_search": 0,
|
||||
"in_list_view": 0,
|
||||
"in_standard_filter": 0,
|
||||
"length": 0,
|
||||
"no_copy": 0,
|
||||
"permlevel": 0,
|
||||
"precision": "",
|
||||
"print_hide": 0,
|
||||
"print_hide_if_no_value": 0,
|
||||
"read_only": 0,
|
||||
"remember_last_selected_value": 0,
|
||||
"report_hide": 0,
|
||||
"reqd": 0,
|
||||
"search_index": 0,
|
||||
"set_only_once": 0,
|
||||
"unique": 0
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"default": "Today",
|
||||
"fieldname": "posting_date",
|
||||
"fieldtype": "Date",
|
||||
"hidden": 0,
|
||||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_global_search": 0,
|
||||
"in_list_view": 1,
|
||||
"in_standard_filter": 0,
|
||||
"label": "Posting Date",
|
||||
"length": 0,
|
||||
"no_copy": 0,
|
||||
"options": "",
|
||||
"permlevel": 0,
|
||||
"precision": "",
|
||||
"print_hide": 0,
|
||||
"print_hide_if_no_value": 0,
|
||||
"read_only": 0,
|
||||
"remember_last_selected_value": 0,
|
||||
"report_hide": 0,
|
||||
"reqd": 1,
|
||||
"search_index": 0,
|
||||
"set_only_once": 0,
|
||||
"unique": 0
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"default": "Today",
|
||||
"fieldname": "due_date",
|
||||
"fieldtype": "Date",
|
||||
"hidden": 0,
|
||||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_global_search": 0,
|
||||
"in_list_view": 1,
|
||||
"in_standard_filter": 0,
|
||||
"label": "Due Date",
|
||||
"length": 0,
|
||||
"no_copy": 0,
|
||||
"permlevel": 0,
|
||||
"precision": "",
|
||||
"print_hide": 0,
|
||||
"print_hide_if_no_value": 0,
|
||||
"read_only": 0,
|
||||
"remember_last_selected_value": 0,
|
||||
"report_hide": 0,
|
||||
"reqd": 1,
|
||||
"search_index": 0,
|
||||
"set_only_once": 0,
|
||||
"unique": 0
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fieldname": "section_break_5",
|
||||
"fieldtype": "Section Break",
|
||||
"hidden": 0,
|
||||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_global_search": 0,
|
||||
"in_list_view": 0,
|
||||
"in_standard_filter": 0,
|
||||
"length": 0,
|
||||
"no_copy": 0,
|
||||
"permlevel": 0,
|
||||
"precision": "",
|
||||
"print_hide": 0,
|
||||
"print_hide_if_no_value": 0,
|
||||
"read_only": 0,
|
||||
"remember_last_selected_value": 0,
|
||||
"report_hide": 0,
|
||||
"reqd": 0,
|
||||
"search_index": 0,
|
||||
"set_only_once": 0,
|
||||
"unique": 0
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"default": "Opening Invoice Item",
|
||||
"fieldname": "item_name",
|
||||
"fieldtype": "Data",
|
||||
"hidden": 0,
|
||||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_global_search": 0,
|
||||
"in_list_view": 1,
|
||||
"in_standard_filter": 0,
|
||||
"label": "Item Name",
|
||||
"length": 0,
|
||||
"no_copy": 0,
|
||||
"options": "",
|
||||
"permlevel": 0,
|
||||
"precision": "",
|
||||
"print_hide": 0,
|
||||
"print_hide_if_no_value": 0,
|
||||
"read_only": 0,
|
||||
"remember_last_selected_value": 0,
|
||||
"report_hide": 0,
|
||||
"reqd": 0,
|
||||
"search_index": 0,
|
||||
"set_only_once": 0,
|
||||
"unique": 0
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"default": "0",
|
||||
"fieldname": "outstanding_amount",
|
||||
"fieldtype": "Currency",
|
||||
"hidden": 0,
|
||||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_global_search": 0,
|
||||
"in_list_view": 1,
|
||||
"in_standard_filter": 0,
|
||||
"label": "Outstanding Amount",
|
||||
"length": 0,
|
||||
"no_copy": 0,
|
||||
"permlevel": 0,
|
||||
"precision": "",
|
||||
"print_hide": 0,
|
||||
"print_hide_if_no_value": 0,
|
||||
"read_only": 0,
|
||||
"remember_last_selected_value": 0,
|
||||
"report_hide": 0,
|
||||
"reqd": 0,
|
||||
"search_index": 0,
|
||||
"set_only_once": 0,
|
||||
"unique": 0
|
||||
}
|
||||
],
|
||||
"has_web_view": 0,
|
||||
"hide_heading": 0,
|
||||
"hide_toolbar": 0,
|
||||
"idx": 0,
|
||||
"image_view": 0,
|
||||
"in_create": 0,
|
||||
"is_submittable": 0,
|
||||
"issingle": 0,
|
||||
"istable": 1,
|
||||
"max_attachments": 0,
|
||||
"modified": "2017-11-15 14:19:00.433148",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Accounts",
|
||||
"name": "Opening Invoice Creation Tool Item",
|
||||
"name_case": "",
|
||||
"owner": "Administrator",
|
||||
"permissions": [],
|
||||
"quick_entry": 1,
|
||||
"read_only": 0,
|
||||
"read_only_onload": 0,
|
||||
"show_name_in_global_search": 0,
|
||||
"sort_field": "modified",
|
||||
"sort_order": "DESC",
|
||||
"track_changes": 1,
|
||||
"track_seen": 0
|
||||
}
|
@ -0,0 +1,10 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# Copyright (c) 2017, Frappe Technologies Pvt. Ltd. and contributors
|
||||
# For license information, please see license.txt
|
||||
|
||||
from __future__ import unicode_literals
|
||||
import frappe
|
||||
from frappe.model.document import Document
|
||||
|
||||
class OpeningInvoiceCreationToolItem(Document):
|
||||
pass
|
@ -369,7 +369,7 @@
|
||||
"in_filter": 0,
|
||||
"in_global_search": 0,
|
||||
"in_list_view": 0,
|
||||
"in_standard_filter": 0,
|
||||
"in_standard_filter": 1,
|
||||
"label": "Company",
|
||||
"length": 0,
|
||||
"no_copy": 0,
|
||||
|
@ -3,8 +3,8 @@
|
||||
|
||||
from __future__ import unicode_literals
|
||||
import frappe
|
||||
from frappe.utils import flt, getdate, cstr
|
||||
from frappe import _
|
||||
from frappe.utils import getdate, cstr, flt
|
||||
from frappe import _, _dict
|
||||
from erpnext.accounts.utils import get_account_currency
|
||||
|
||||
def execute(filters=None):
|
||||
@ -163,129 +163,89 @@ def get_data_with_opening_closing(filters, account_details, gl_entries):
|
||||
data = []
|
||||
gle_map = initialize_gle_map(gl_entries)
|
||||
|
||||
opening, total_debit, total_credit, opening_in_account_currency, total_debit_in_account_currency, \
|
||||
total_credit_in_account_currency, gle_map = get_accountwise_gle(filters, gl_entries, gle_map)
|
||||
totals, entries = get_accountwise_gle(filters, gl_entries, gle_map)
|
||||
|
||||
# Opening for filtered account
|
||||
if filters.get("account") or filters.get("party"):
|
||||
data += [get_balance_row(_("Opening"), opening, opening_in_account_currency), {}]
|
||||
data.append(totals.opening)
|
||||
|
||||
if filters.get("group_by_account"):
|
||||
for acc, acc_dict in gle_map.items():
|
||||
if acc_dict.entries:
|
||||
# Opening for individual ledger, if grouped by account
|
||||
data.append(get_balance_row(_("Opening"), acc_dict.opening,
|
||||
acc_dict.opening_in_account_currency))
|
||||
# opening
|
||||
data.append({})
|
||||
data.append(acc_dict.totals.opening)
|
||||
|
||||
data += acc_dict.entries
|
||||
|
||||
# Totals and closing for individual ledger, if grouped by account
|
||||
account_closing = acc_dict.opening + acc_dict.total_debit - acc_dict.total_credit
|
||||
account_closing_in_account_currency = acc_dict.opening_in_account_currency \
|
||||
+ acc_dict.total_debit_in_account_currency - acc_dict.total_credit_in_account_currency
|
||||
# totals
|
||||
data.append(acc_dict.totals.total)
|
||||
|
||||
data += [{"account": "'" + _("Totals") + "'", "debit": acc_dict.total_debit,
|
||||
"credit": acc_dict.total_credit},
|
||||
get_balance_row(_("Closing (Opening + Totals)"),
|
||||
account_closing, account_closing_in_account_currency), {}]
|
||||
# closing
|
||||
data.append(acc_dict.totals.closing)
|
||||
data.append({})
|
||||
|
||||
else:
|
||||
for gl in gl_entries:
|
||||
if gl.posting_date >= getdate(filters.from_date) and gl.posting_date <= getdate(filters.to_date) \
|
||||
and gl.is_opening == "No":
|
||||
data.append(gl)
|
||||
data += entries
|
||||
|
||||
# totals
|
||||
data.append(totals.total)
|
||||
|
||||
# Total debit and credit between from and to date
|
||||
if total_debit or total_credit:
|
||||
data.append({
|
||||
"account": "'" + _("Totals") + "'",
|
||||
"debit": total_debit,
|
||||
"credit": total_credit,
|
||||
"debit_in_account_currency": total_debit_in_account_currency,
|
||||
"credit_in_account_currency": total_credit_in_account_currency
|
||||
})
|
||||
|
||||
# Closing for filtered account
|
||||
if filters.get("account") or filters.get("party"):
|
||||
closing = opening + total_debit - total_credit
|
||||
closing_in_account_currency = opening_in_account_currency + \
|
||||
total_debit_in_account_currency - total_credit_in_account_currency
|
||||
|
||||
data.append(get_balance_row(_("Closing (Opening + Totals)"),
|
||||
closing, closing_in_account_currency))
|
||||
# closing
|
||||
data.append(totals.closing)
|
||||
|
||||
return data
|
||||
|
||||
def get_totals_dict():
|
||||
def _get_debit_credit_dict(label):
|
||||
return _dict(
|
||||
account = "'{0}'".format(label),
|
||||
debit = 0.0,
|
||||
credit = 0.0,
|
||||
debit_in_account_currency = 0.0,
|
||||
credit_in_account_currency = 0.0
|
||||
)
|
||||
return _dict(
|
||||
opening = _get_debit_credit_dict(_('Opening')),
|
||||
total = _get_debit_credit_dict(_('Total')),
|
||||
closing = _get_debit_credit_dict(_('Closing (Opening + Total)'))
|
||||
)
|
||||
|
||||
def initialize_gle_map(gl_entries):
|
||||
gle_map = frappe._dict()
|
||||
for gle in gl_entries:
|
||||
gle_map.setdefault(gle.account, frappe._dict({
|
||||
"opening": 0,
|
||||
"opening_in_account_currency": 0,
|
||||
"entries": [],
|
||||
"total_debit": 0,
|
||||
"total_debit_in_account_currency": 0,
|
||||
"total_credit": 0,
|
||||
"total_credit_in_account_currency": 0,
|
||||
"closing": 0,
|
||||
"closing_in_account_currency": 0
|
||||
}))
|
||||
gle_map.setdefault(gle.account, _dict(totals = get_totals_dict(), entries = []))
|
||||
return gle_map
|
||||
|
||||
def get_accountwise_gle(filters, gl_entries, gle_map):
|
||||
opening, total_debit, total_credit = 0, 0, 0
|
||||
opening_in_account_currency, total_debit_in_account_currency, total_credit_in_account_currency = 0, 0, 0
|
||||
totals = get_totals_dict()
|
||||
entries = []
|
||||
|
||||
def update_value_in_dict(data, key, gle):
|
||||
data[key].debit += flt(gle.debit)
|
||||
data[key].credit += flt(gle.credit)
|
||||
|
||||
data[key].debit_in_account_currency += flt(gle.debit_in_account_currency)
|
||||
data[key].credit_in_account_currency += flt(gle.credit_in_account_currency)
|
||||
|
||||
|
||||
from_date, to_date = getdate(filters.from_date), getdate(filters.to_date)
|
||||
for gle in gl_entries:
|
||||
amount = flt(gle.debit, 3) - flt(gle.credit, 3)
|
||||
amount_in_account_currency = flt(gle.debit_in_account_currency, 3) - flt(gle.credit_in_account_currency, 3)
|
||||
|
||||
if (filters.get("account") or filters.get("party") or filters.get("group_by_account")) \
|
||||
and (gle.posting_date < from_date or cstr(gle.is_opening) == "Yes"):
|
||||
|
||||
gle_map[gle.account].opening += amount
|
||||
if filters.get("show_in_account_currency"):
|
||||
gle_map[gle.account].opening_in_account_currency += amount_in_account_currency
|
||||
|
||||
if filters.get("account") or filters.get("party"):
|
||||
opening += amount
|
||||
if filters.get("show_in_account_currency"):
|
||||
opening_in_account_currency += amount_in_account_currency
|
||||
if gle.posting_date < from_date or cstr(gle.is_opening) == "Yes":
|
||||
update_value_in_dict(gle_map[gle.account].totals, 'opening', gle)
|
||||
update_value_in_dict(totals, 'opening', gle)
|
||||
|
||||
elif gle.posting_date <= to_date:
|
||||
gle_map[gle.account].entries.append(gle)
|
||||
gle_map[gle.account].total_debit += flt(gle.debit, 3)
|
||||
gle_map[gle.account].total_credit += flt(gle.credit, 3)
|
||||
update_value_in_dict(gle_map[gle.account].totals, 'total', gle)
|
||||
update_value_in_dict(totals, 'total', gle)
|
||||
if filters.get("group_by_account"):
|
||||
gle_map[gle.account].entries.append(gle)
|
||||
else:
|
||||
entries.append(gle)
|
||||
|
||||
total_debit += flt(gle.debit, 3)
|
||||
total_credit += flt(gle.credit, 3)
|
||||
update_value_in_dict(gle_map[gle.account].totals, 'closing', gle)
|
||||
update_value_in_dict(totals, 'closing', gle)
|
||||
|
||||
if filters.get("show_in_account_currency"):
|
||||
gle_map[gle.account].total_debit_in_account_currency += flt(gle.debit_in_account_currency, 3)
|
||||
gle_map[gle.account].total_credit_in_account_currency += flt(gle.credit_in_account_currency, 3)
|
||||
|
||||
total_debit_in_account_currency += flt(gle.debit_in_account_currency, 3)
|
||||
total_credit_in_account_currency += flt(gle.credit_in_account_currency, 3)
|
||||
|
||||
return opening, total_debit, total_credit, opening_in_account_currency, \
|
||||
total_debit_in_account_currency, total_credit_in_account_currency, gle_map
|
||||
|
||||
def get_balance_row(label, balance, balance_in_account_currency=None):
|
||||
balance_row = {
|
||||
"account": "'" + label + "'",
|
||||
"debit": balance if balance > 0 else 0,
|
||||
"credit": -1*balance if balance < 0 else 0
|
||||
}
|
||||
|
||||
if balance_in_account_currency != None:
|
||||
balance_row.update({
|
||||
"debit_in_account_currency": balance_in_account_currency if balance_in_account_currency > 0 else 0,
|
||||
"credit_in_account_currency": -1*balance_in_account_currency if balance_in_account_currency < 0 else 0
|
||||
})
|
||||
|
||||
return balance_row
|
||||
return totals, entries
|
||||
|
||||
def get_result_as_list(data, filters):
|
||||
result = []
|
||||
|
@ -15,6 +15,11 @@
|
||||
"supplier_name": "_Test Supplier 1",
|
||||
"supplier_type": "_Test Supplier Type"
|
||||
},
|
||||
{
|
||||
"doctype": "Supplier",
|
||||
"supplier_name": "_Test Supplier 2",
|
||||
"supplier_type": "_Test Supplier Type"
|
||||
},
|
||||
{
|
||||
"doctype": "Supplier",
|
||||
"supplier_name": "_Test Supplier USD",
|
||||
|
@ -284,6 +284,11 @@ def get_data():
|
||||
"name": "Cheque Print Template",
|
||||
"description": _("Setup cheque dimensions for printing")
|
||||
},
|
||||
{
|
||||
"type": "doctype",
|
||||
"name": "Opening Invoice Creation Tool",
|
||||
"description": _("Make Opening Sales and Purchase Invoices")
|
||||
},
|
||||
]
|
||||
},
|
||||
{
|
||||
|
@ -83,9 +83,6 @@ class AccountsController(TransactionBase):
|
||||
self.set(fieldname, today())
|
||||
break
|
||||
|
||||
# set taxes table if missing from `taxes_and_charges`
|
||||
self.set_taxes()
|
||||
|
||||
def calculate_taxes_and_totals(self):
|
||||
from erpnext.controllers.taxes_and_totals import calculate_taxes_and_totals
|
||||
calculate_taxes_and_totals(self)
|
||||
|
Binary file not shown.
After Width: | Height: | Size: 137 KiB |
@ -1,4 +1,4 @@
|
||||
#Updating Opening Balance in Accounts
|
||||
# Updating Opening Balance in Accounts
|
||||
|
||||
If you are a new company you can start using ERPNext accounting module by going to chart of accounts. However, if you are migrating from a legacy accounting system like Tally or a Fox Pro based software
|
||||
|
||||
@ -18,23 +18,23 @@ If you were using another accounting software before, firstly you should close f
|
||||
|
||||
###Opening Entry
|
||||
|
||||
####Step 1: New Journal Entry
|
||||
#### Step 1: New Journal Entry
|
||||
|
||||
To open new Journal Entry, go to:
|
||||
|
||||
`Explore > Accounts > Journal Entry`
|
||||
|
||||
####Step 2: Entry Type
|
||||
#### Step 2: Entry Type
|
||||
|
||||
If Entry Type is selected as Opening Entry, all the Balance Sheet Accounts will be auto-fetched in the Journal Entry.
|
||||
|
||||
<img class="screenshot" alt="Opening Account" src="/docs/assets/img/accounts/opening-account-1.png">
|
||||
|
||||
####Step 3: Posting Date
|
||||
#### Step 3: Posting Date
|
||||
|
||||
Select Posting Date on which Accounts Opening Balance will be updated.
|
||||
|
||||
####Step 4: Enter Debit/Credit Value
|
||||
#### Step 4: Enter Debit/Credit Value
|
||||
|
||||
For each Account, enter opening value in the Debit or Credit column. As per the double entry valuation system, Total Debit value in a entry must be equal to Total Credit value.
|
||||
|
||||
@ -86,9 +86,9 @@ To update stock opening balance, create [Stock Reconciliation entry](/docs/user/
|
||||
|
||||
Opening balance for the fixed asset account should be updated via Journal Entry. Assets which are not fully depreciated should be added in the [Asset master](/docs/user/manual/en/accounts/managing-fixed-assets.html). For adding Assets in your possession, ensure to check **Is Existing Asset** field.
|
||||
|
||||
### Outstanding Invoices
|
||||
### Outstanding Payables and Receivables
|
||||
|
||||
After opening Journal Entries are made, you will need to enter each Sales Invoice and Purchase Invoice that is yet to be paid.
|
||||
After opening Journal Entries are made, you will need to enter the Sales Invoice and Purchase Invoice that is yet to be paid.
|
||||
|
||||
Since you have already booked the income or expense on these invoices in the previous period, select **Temporary Opening** in the “Income” and “Expense” accounts.
|
||||
|
||||
@ -96,4 +96,12 @@ Since you have already booked the income or expense on these invoices in the pre
|
||||
|
||||
If you don’t care what items are in that invoice, just make a dummy item entry in the Invoice. Item code in the Invoice is not necessary, so it should not be such a problem.
|
||||
|
||||
You can also do this quickly using the **Opening Invoice Creation Tool**
|
||||
|
||||
To use this tool, just type "Opening Invoice" in the search bar and select the **Opening Invoice Creation Tool**
|
||||
|
||||
Here, select the company and type of invoice (sales or purchase) and add a line item for each invoice you want to create.
|
||||
|
||||
<img class="screenshot" alt="Opening Invoice Creation Tool" src="/docs/assets/img/accounts/opening-invoice-creation-tool.png">
|
||||
|
||||
{next}
|
||||
|
Loading…
x
Reference in New Issue
Block a user