Merge branch 'version-13-hotfix' into backport/version-13-hotfix/27086
This commit is contained in:
@@ -18,6 +18,7 @@
|
|||||||
"delete_linked_ledger_entries",
|
"delete_linked_ledger_entries",
|
||||||
"book_asset_depreciation_entry_automatically",
|
"book_asset_depreciation_entry_automatically",
|
||||||
"unlink_advance_payment_on_cancelation_of_order",
|
"unlink_advance_payment_on_cancelation_of_order",
|
||||||
|
"enable_common_party_accounting",
|
||||||
"post_change_gl_entries",
|
"post_change_gl_entries",
|
||||||
"enable_discount_accounting",
|
"enable_discount_accounting",
|
||||||
"tax_settings_section",
|
"tax_settings_section",
|
||||||
@@ -269,6 +270,12 @@
|
|||||||
"fieldname": "enable_discount_accounting",
|
"fieldname": "enable_discount_accounting",
|
||||||
"fieldtype": "Check",
|
"fieldtype": "Check",
|
||||||
"label": "Enable Discount Accounting"
|
"label": "Enable Discount Accounting"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"default": "0",
|
||||||
|
"fieldname": "enable_common_party_accounting",
|
||||||
|
"fieldtype": "Check",
|
||||||
|
"label": "Enable Common Party Accounting"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"icon": "icon-cog",
|
"icon": "icon-cog",
|
||||||
@@ -276,7 +283,7 @@
|
|||||||
"index_web_pages_for_search": 1,
|
"index_web_pages_for_search": 1,
|
||||||
"issingle": 1,
|
"issingle": 1,
|
||||||
"links": [],
|
"links": [],
|
||||||
"modified": "2021-07-12 18:54:29.084958",
|
"modified": "2021-08-19 11:17:38.788054",
|
||||||
"modified_by": "Administrator",
|
"modified_by": "Administrator",
|
||||||
"module": "Accounts",
|
"module": "Accounts",
|
||||||
"name": "Accounts Settings",
|
"name": "Accounts Settings",
|
||||||
|
|||||||
0
erpnext/accounts/doctype/party_link/__init__.py
Normal file
0
erpnext/accounts/doctype/party_link/__init__.py
Normal file
33
erpnext/accounts/doctype/party_link/party_link.js
Normal file
33
erpnext/accounts/doctype/party_link/party_link.js
Normal file
@@ -0,0 +1,33 @@
|
|||||||
|
// Copyright (c) 2021, Frappe Technologies Pvt. Ltd. and contributors
|
||||||
|
// For license information, please see license.txt
|
||||||
|
|
||||||
|
frappe.ui.form.on('Party Link', {
|
||||||
|
refresh: function(frm) {
|
||||||
|
frm.set_query('primary_role', () => {
|
||||||
|
return {
|
||||||
|
filters: {
|
||||||
|
name: ['in', ['Customer', 'Supplier']]
|
||||||
|
}
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
|
frm.set_query('secondary_role', () => {
|
||||||
|
let party_types = Object.keys(frappe.boot.party_account_types)
|
||||||
|
.filter(p => p != frm.doc.primary_role);
|
||||||
|
return {
|
||||||
|
filters: {
|
||||||
|
name: ['in', party_types]
|
||||||
|
}
|
||||||
|
};
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
|
primary_role(frm) {
|
||||||
|
frm.set_value('primary_party', '');
|
||||||
|
frm.set_value('secondary_role', '');
|
||||||
|
},
|
||||||
|
|
||||||
|
secondary_role(frm) {
|
||||||
|
frm.set_value('secondary_party', '');
|
||||||
|
}
|
||||||
|
});
|
||||||
102
erpnext/accounts/doctype/party_link/party_link.json
Normal file
102
erpnext/accounts/doctype/party_link/party_link.json
Normal file
@@ -0,0 +1,102 @@
|
|||||||
|
{
|
||||||
|
"actions": [],
|
||||||
|
"autoname": "ACC-PT-LNK-.###.",
|
||||||
|
"creation": "2021-08-18 21:06:53.027695",
|
||||||
|
"doctype": "DocType",
|
||||||
|
"editable_grid": 1,
|
||||||
|
"engine": "InnoDB",
|
||||||
|
"field_order": [
|
||||||
|
"primary_role",
|
||||||
|
"secondary_role",
|
||||||
|
"column_break_2",
|
||||||
|
"primary_party",
|
||||||
|
"secondary_party"
|
||||||
|
],
|
||||||
|
"fields": [
|
||||||
|
{
|
||||||
|
"fieldname": "primary_role",
|
||||||
|
"fieldtype": "Link",
|
||||||
|
"in_list_view": 1,
|
||||||
|
"label": "Primary Role",
|
||||||
|
"options": "DocType",
|
||||||
|
"reqd": 1
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldname": "column_break_2",
|
||||||
|
"fieldtype": "Column Break"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"depends_on": "primary_role",
|
||||||
|
"fieldname": "secondary_role",
|
||||||
|
"fieldtype": "Link",
|
||||||
|
"label": "Secondary Role",
|
||||||
|
"mandatory_depends_on": "primary_role",
|
||||||
|
"options": "DocType"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"depends_on": "primary_role",
|
||||||
|
"fieldname": "primary_party",
|
||||||
|
"fieldtype": "Dynamic Link",
|
||||||
|
"label": "Primary Party",
|
||||||
|
"mandatory_depends_on": "primary_role",
|
||||||
|
"options": "primary_role"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"depends_on": "secondary_role",
|
||||||
|
"fieldname": "secondary_party",
|
||||||
|
"fieldtype": "Dynamic Link",
|
||||||
|
"label": "Secondary Party",
|
||||||
|
"mandatory_depends_on": "secondary_role",
|
||||||
|
"options": "secondary_role"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"index_web_pages_for_search": 1,
|
||||||
|
"links": [],
|
||||||
|
"modified": "2021-08-25 20:08:56.761150",
|
||||||
|
"modified_by": "Administrator",
|
||||||
|
"module": "Accounts",
|
||||||
|
"name": "Party Link",
|
||||||
|
"owner": "Administrator",
|
||||||
|
"permissions": [
|
||||||
|
{
|
||||||
|
"create": 1,
|
||||||
|
"delete": 1,
|
||||||
|
"email": 1,
|
||||||
|
"export": 1,
|
||||||
|
"print": 1,
|
||||||
|
"read": 1,
|
||||||
|
"report": 1,
|
||||||
|
"role": "System Manager",
|
||||||
|
"share": 1,
|
||||||
|
"write": 1
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"create": 1,
|
||||||
|
"delete": 1,
|
||||||
|
"email": 1,
|
||||||
|
"export": 1,
|
||||||
|
"print": 1,
|
||||||
|
"read": 1,
|
||||||
|
"report": 1,
|
||||||
|
"role": "Accounts Manager",
|
||||||
|
"share": 1,
|
||||||
|
"write": 1
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"create": 1,
|
||||||
|
"delete": 1,
|
||||||
|
"email": 1,
|
||||||
|
"export": 1,
|
||||||
|
"print": 1,
|
||||||
|
"read": 1,
|
||||||
|
"report": 1,
|
||||||
|
"role": "Accounts User",
|
||||||
|
"share": 1,
|
||||||
|
"write": 1
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"sort_field": "modified",
|
||||||
|
"sort_order": "DESC",
|
||||||
|
"title_field": "primary_party",
|
||||||
|
"track_changes": 1
|
||||||
|
}
|
||||||
26
erpnext/accounts/doctype/party_link/party_link.py
Normal file
26
erpnext/accounts/doctype/party_link/party_link.py
Normal file
@@ -0,0 +1,26 @@
|
|||||||
|
# Copyright (c) 2021, Frappe Technologies Pvt. Ltd. and contributors
|
||||||
|
# For license information, please see license.txt
|
||||||
|
|
||||||
|
import frappe
|
||||||
|
from frappe import _
|
||||||
|
from frappe.model.document import Document
|
||||||
|
|
||||||
|
class PartyLink(Document):
|
||||||
|
def validate(self):
|
||||||
|
if self.primary_role not in ['Customer', 'Supplier']:
|
||||||
|
frappe.throw(_("Allowed primary roles are 'Customer' and 'Supplier'. Please select one of these roles only."),
|
||||||
|
title=_("Invalid Primary Role"))
|
||||||
|
|
||||||
|
existing_party_link = frappe.get_all('Party Link', {
|
||||||
|
'primary_party': self.secondary_party
|
||||||
|
}, pluck="primary_role")
|
||||||
|
if existing_party_link:
|
||||||
|
frappe.throw(_('{} {} is already linked with another {}')
|
||||||
|
.format(self.secondary_role, self.secondary_party, existing_party_link[0]))
|
||||||
|
|
||||||
|
existing_party_link = frappe.get_all('Party Link', {
|
||||||
|
'secondary_party': self.primary_party
|
||||||
|
}, pluck="primary_role")
|
||||||
|
if existing_party_link:
|
||||||
|
frappe.throw(_('{} {} is already linked with another {}')
|
||||||
|
.format(self.primary_role, self.primary_party, existing_party_link[0]))
|
||||||
8
erpnext/accounts/doctype/party_link/test_party_link.py
Normal file
8
erpnext/accounts/doctype/party_link/test_party_link.py
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
# Copyright (c) 2021, Frappe Technologies Pvt. Ltd. and Contributors
|
||||||
|
# See license.txt
|
||||||
|
|
||||||
|
# import frappe
|
||||||
|
import unittest
|
||||||
|
|
||||||
|
class TestPartyLink(unittest.TestCase):
|
||||||
|
pass
|
||||||
@@ -413,6 +413,8 @@ class PurchaseInvoice(BuyingController):
|
|||||||
self.update_project()
|
self.update_project()
|
||||||
update_linked_doc(self.doctype, self.name, self.inter_company_invoice_reference)
|
update_linked_doc(self.doctype, self.name, self.inter_company_invoice_reference)
|
||||||
|
|
||||||
|
self.process_common_party_accounting()
|
||||||
|
|
||||||
def make_gl_entries(self, gl_entries=None, from_repost=False):
|
def make_gl_entries(self, gl_entries=None, from_repost=False):
|
||||||
if not gl_entries:
|
if not gl_entries:
|
||||||
gl_entries = self.get_gl_entries()
|
gl_entries = self.get_gl_entries()
|
||||||
|
|||||||
@@ -253,6 +253,8 @@ class SalesInvoice(SellingController):
|
|||||||
if "Healthcare" in active_domains:
|
if "Healthcare" in active_domains:
|
||||||
manage_invoice_submit_cancel(self, "on_submit")
|
manage_invoice_submit_cancel(self, "on_submit")
|
||||||
|
|
||||||
|
self.process_common_party_accounting()
|
||||||
|
|
||||||
def validate_pos_return(self):
|
def validate_pos_return(self):
|
||||||
|
|
||||||
if self.is_pos and self.is_return:
|
if self.is_pos and self.is_return:
|
||||||
|
|||||||
@@ -1107,6 +1107,18 @@ class TestSalesInvoice(unittest.TestCase):
|
|||||||
self.assertEqual(frappe.db.get_value("Sales Invoice", si.name, "outstanding_amount"), 1500)
|
self.assertEqual(frappe.db.get_value("Sales Invoice", si.name, "outstanding_amount"), 1500)
|
||||||
|
|
||||||
|
|
||||||
|
def test_incoming_rate_for_stand_alone_credit_note(self):
|
||||||
|
return_si = create_sales_invoice(is_return=1, update_stock=1, qty=-1, rate=90000, incoming_rate=10,
|
||||||
|
company='_Test Company with perpetual inventory', warehouse='Stores - TCP1', debit_to='Debtors - TCP1',
|
||||||
|
income_account='Sales - TCP1', expense_account='Cost of Goods Sold - TCP1', cost_center='Main - TCP1')
|
||||||
|
|
||||||
|
incoming_rate = frappe.db.get_value('Stock Ledger Entry', {'voucher_no': return_si.name}, 'incoming_rate')
|
||||||
|
debit_amount = frappe.db.get_value('GL Entry',
|
||||||
|
{'voucher_no': return_si.name, 'account': 'Stock In Hand - TCP1'}, 'debit')
|
||||||
|
|
||||||
|
self.assertEqual(debit_amount, 10.0)
|
||||||
|
self.assertEqual(incoming_rate, 10.0)
|
||||||
|
|
||||||
def test_discount_on_net_total(self):
|
def test_discount_on_net_total(self):
|
||||||
si = frappe.copy_doc(test_records[2])
|
si = frappe.copy_doc(test_records[2])
|
||||||
si.apply_discount_on = "Net Total"
|
si.apply_discount_on = "Net Total"
|
||||||
@@ -2096,6 +2108,50 @@ class TestSalesInvoice(unittest.TestCase):
|
|||||||
check_gl_entries(self, si.name, expected_gle, add_days(nowdate(), -1))
|
check_gl_entries(self, si.name, expected_gle, add_days(nowdate(), -1))
|
||||||
enable_discount_accounting(enable=0)
|
enable_discount_accounting(enable=0)
|
||||||
|
|
||||||
|
def test_sales_invoice_against_supplier(self):
|
||||||
|
from erpnext.accounts.doctype.opening_invoice_creation_tool.test_opening_invoice_creation_tool import make_customer
|
||||||
|
from erpnext.buying.doctype.supplier.test_supplier import create_supplier
|
||||||
|
|
||||||
|
# create a customer
|
||||||
|
customer = make_customer(customer="_Test Common Supplier")
|
||||||
|
# create a supplier
|
||||||
|
supplier = create_supplier(supplier_name="_Test Common Supplier").name
|
||||||
|
|
||||||
|
# create a party link between customer & supplier
|
||||||
|
# set primary role as supplier
|
||||||
|
party_link = frappe.new_doc("Party Link")
|
||||||
|
party_link.primary_role = "Supplier"
|
||||||
|
party_link.primary_party = supplier
|
||||||
|
party_link.secondary_role = "Customer"
|
||||||
|
party_link.secondary_party = customer
|
||||||
|
party_link.save()
|
||||||
|
|
||||||
|
# enable common party accounting
|
||||||
|
frappe.db.set_value('Accounts Settings', None, 'enable_common_party_accounting', 1)
|
||||||
|
|
||||||
|
# create a sales invoice
|
||||||
|
si = create_sales_invoice(customer=customer, parent_cost_center="_Test Cost Center - _TC")
|
||||||
|
|
||||||
|
# check outstanding of sales invoice
|
||||||
|
si.reload()
|
||||||
|
self.assertEqual(si.status, 'Paid')
|
||||||
|
self.assertEqual(flt(si.outstanding_amount), 0.0)
|
||||||
|
|
||||||
|
# check creation of journal entry
|
||||||
|
jv = frappe.get_all('Journal Entry Account', {
|
||||||
|
'account': si.debit_to,
|
||||||
|
'party_type': 'Customer',
|
||||||
|
'party': si.customer,
|
||||||
|
'reference_type': si.doctype,
|
||||||
|
'reference_name': si.name
|
||||||
|
}, pluck='credit_in_account_currency')
|
||||||
|
|
||||||
|
self.assertTrue(jv)
|
||||||
|
self.assertEqual(jv[0], si.grand_total)
|
||||||
|
|
||||||
|
party_link.delete()
|
||||||
|
frappe.db.set_value('Accounts Settings', None, 'enable_common_party_accounting', 0)
|
||||||
|
|
||||||
def get_sales_invoice_for_e_invoice():
|
def get_sales_invoice_for_e_invoice():
|
||||||
si = make_sales_invoice_for_ewaybill()
|
si = make_sales_invoice_for_ewaybill()
|
||||||
si.naming_series = 'INV-2020-.#####'
|
si.naming_series = 'INV-2020-.#####'
|
||||||
@@ -2308,7 +2364,8 @@ def create_sales_invoice(**args):
|
|||||||
"discount_amount": args.discount_amount or 0,
|
"discount_amount": args.discount_amount or 0,
|
||||||
"cost_center": args.cost_center or "_Test Cost Center - _TC",
|
"cost_center": args.cost_center or "_Test Cost Center - _TC",
|
||||||
"serial_no": args.serial_no,
|
"serial_no": args.serial_no,
|
||||||
"conversion_factor": 1
|
"conversion_factor": 1,
|
||||||
|
"incoming_rate": args.incoming_rate or 0
|
||||||
})
|
})
|
||||||
|
|
||||||
if not args.do_not_save:
|
if not args.do_not_save:
|
||||||
|
|||||||
@@ -53,7 +53,6 @@
|
|||||||
"column_break_24",
|
"column_break_24",
|
||||||
"base_net_rate",
|
"base_net_rate",
|
||||||
"base_net_amount",
|
"base_net_amount",
|
||||||
"incoming_rate",
|
|
||||||
"drop_ship",
|
"drop_ship",
|
||||||
"delivered_by_supplier",
|
"delivered_by_supplier",
|
||||||
"accounting",
|
"accounting",
|
||||||
@@ -81,6 +80,7 @@
|
|||||||
"target_warehouse",
|
"target_warehouse",
|
||||||
"quality_inspection",
|
"quality_inspection",
|
||||||
"batch_no",
|
"batch_no",
|
||||||
|
"incoming_rate",
|
||||||
"col_break5",
|
"col_break5",
|
||||||
"allow_zero_valuation_rate",
|
"allow_zero_valuation_rate",
|
||||||
"serial_no",
|
"serial_no",
|
||||||
@@ -808,12 +808,12 @@
|
|||||||
"read_only": 1
|
"read_only": 1
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
"depends_on": "eval:parent.is_return && parent.update_stock && !parent.return_against",
|
||||||
"fieldname": "incoming_rate",
|
"fieldname": "incoming_rate",
|
||||||
"fieldtype": "Currency",
|
"fieldtype": "Currency",
|
||||||
"label": "Incoming Rate",
|
"label": "Incoming Rate (Costing)",
|
||||||
"no_copy": 1,
|
"no_copy": 1,
|
||||||
"print_hide": 1,
|
"print_hide": 1
|
||||||
"read_only": 1
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"depends_on": "eval: doc.uom != doc.stock_uom",
|
"depends_on": "eval: doc.uom != doc.stock_uom",
|
||||||
@@ -834,7 +834,7 @@
|
|||||||
"idx": 1,
|
"idx": 1,
|
||||||
"istable": 1,
|
"istable": 1,
|
||||||
"links": [],
|
"links": [],
|
||||||
"modified": "2021-08-12 20:15:42.668399",
|
"modified": "2021-08-19 13:41:53.435827",
|
||||||
"modified_by": "Administrator",
|
"modified_by": "Administrator",
|
||||||
"module": "Accounts",
|
"module": "Accounts",
|
||||||
"name": "Sales Invoice Item",
|
"name": "Sales Invoice Item",
|
||||||
|
|||||||
@@ -14,7 +14,7 @@ from erpnext.accounts.utils import get_fiscal_years, validate_fiscal_year, get_a
|
|||||||
from erpnext.utilities.transaction_base import TransactionBase
|
from erpnext.utilities.transaction_base import TransactionBase
|
||||||
from erpnext.buying.utils import update_last_purchase_rate
|
from erpnext.buying.utils import update_last_purchase_rate
|
||||||
from erpnext.controllers.sales_and_purchase_return import validate_return
|
from erpnext.controllers.sales_and_purchase_return import validate_return
|
||||||
from erpnext.accounts.party import get_party_account_currency, validate_party_frozen_disabled
|
from erpnext.accounts.party import get_party_account_currency, validate_party_frozen_disabled, get_party_account
|
||||||
from erpnext.accounts.doctype.pricing_rule.utils import (apply_pricing_rule_on_transaction,
|
from erpnext.accounts.doctype.pricing_rule.utils import (apply_pricing_rule_on_transaction,
|
||||||
apply_pricing_rule_for_free_items, get_applied_pricing_rules)
|
apply_pricing_rule_for_free_items, get_applied_pricing_rules)
|
||||||
from erpnext.exceptions import InvalidCurrency
|
from erpnext.exceptions import InvalidCurrency
|
||||||
@@ -1368,6 +1368,67 @@ class AccountsController(TransactionBase):
|
|||||||
|
|
||||||
return False
|
return False
|
||||||
|
|
||||||
|
def process_common_party_accounting(self):
|
||||||
|
is_invoice = self.doctype in ['Sales Invoice', 'Purchase Invoice']
|
||||||
|
if not is_invoice:
|
||||||
|
return
|
||||||
|
|
||||||
|
if frappe.db.get_single_value('Accounts Settings', 'enable_common_party_accounting'):
|
||||||
|
party_link = self.get_common_party_link()
|
||||||
|
if party_link and self.outstanding_amount:
|
||||||
|
self.create_advance_and_reconcile(party_link)
|
||||||
|
|
||||||
|
def get_common_party_link(self):
|
||||||
|
party_type, party = self.get_party()
|
||||||
|
return frappe.db.get_value(
|
||||||
|
doctype='Party Link',
|
||||||
|
filters={'secondary_role': party_type, 'secondary_party': party},
|
||||||
|
fieldname=['primary_role', 'primary_party'],
|
||||||
|
as_dict=True
|
||||||
|
)
|
||||||
|
|
||||||
|
def create_advance_and_reconcile(self, party_link):
|
||||||
|
secondary_party_type, secondary_party = self.get_party()
|
||||||
|
primary_party_type, primary_party = party_link.primary_role, party_link.primary_party
|
||||||
|
|
||||||
|
primary_account = get_party_account(primary_party_type, primary_party, self.company)
|
||||||
|
secondary_account = get_party_account(secondary_party_type, secondary_party, self.company)
|
||||||
|
|
||||||
|
jv = frappe.new_doc('Journal Entry')
|
||||||
|
jv.voucher_type = 'Journal Entry'
|
||||||
|
jv.posting_date = self.posting_date
|
||||||
|
jv.company = self.company
|
||||||
|
jv.remark = 'Adjustment for {} {}'.format(self.doctype, self.name)
|
||||||
|
|
||||||
|
reconcilation_entry = frappe._dict()
|
||||||
|
advance_entry = frappe._dict()
|
||||||
|
|
||||||
|
reconcilation_entry.account = secondary_account
|
||||||
|
reconcilation_entry.party_type = secondary_party_type
|
||||||
|
reconcilation_entry.party = secondary_party
|
||||||
|
reconcilation_entry.reference_type = self.doctype
|
||||||
|
reconcilation_entry.reference_name = self.name
|
||||||
|
reconcilation_entry.cost_center = self.cost_center
|
||||||
|
|
||||||
|
advance_entry.account = primary_account
|
||||||
|
advance_entry.party_type = primary_party_type
|
||||||
|
advance_entry.party = primary_party
|
||||||
|
advance_entry.cost_center = self.cost_center
|
||||||
|
advance_entry.is_advance = 'Yes'
|
||||||
|
|
||||||
|
if self.doctype == 'Sales Invoice':
|
||||||
|
reconcilation_entry.credit_in_account_currency = self.outstanding_amount
|
||||||
|
advance_entry.debit_in_account_currency = self.outstanding_amount
|
||||||
|
else:
|
||||||
|
advance_entry.credit_in_account_currency = self.outstanding_amount
|
||||||
|
reconcilation_entry.debit_in_account_currency = self.outstanding_amount
|
||||||
|
|
||||||
|
jv.append('accounts', reconcilation_entry)
|
||||||
|
jv.append('accounts', advance_entry)
|
||||||
|
|
||||||
|
jv.save()
|
||||||
|
jv.submit()
|
||||||
|
|
||||||
@frappe.whitelist()
|
@frappe.whitelist()
|
||||||
def get_tax_rate(account_head):
|
def get_tax_rate(account_head):
|
||||||
return frappe.db.get_value("Account", account_head, ["tax_rate", "account_name"], as_dict=True)
|
return frappe.db.get_value("Account", account_head, ["tax_rate", "account_name"], as_dict=True)
|
||||||
|
|||||||
@@ -394,8 +394,22 @@ def get_rate_for_return(voucher_type, voucher_no, item_code, return_against=None
|
|||||||
if not return_against:
|
if not return_against:
|
||||||
return_against = frappe.get_cached_value(voucher_type, voucher_no, "return_against")
|
return_against = frappe.get_cached_value(voucher_type, voucher_no, "return_against")
|
||||||
|
|
||||||
if not return_against and voucher_type == 'Sales Invoice' and sle:
|
return_against_item_field = get_return_against_item_fields(voucher_type)
|
||||||
return get_incoming_rate({
|
|
||||||
|
filters = get_filters(voucher_type, voucher_no, voucher_detail_no,
|
||||||
|
return_against, item_code, return_against_item_field, item_row)
|
||||||
|
|
||||||
|
if voucher_type in ("Purchase Receipt", "Purchase Invoice"):
|
||||||
|
select_field = "incoming_rate"
|
||||||
|
else:
|
||||||
|
select_field = "abs(stock_value_difference / actual_qty)"
|
||||||
|
|
||||||
|
rate = flt(frappe.db.get_value("Stock Ledger Entry", filters, select_field))
|
||||||
|
if not (rate and return_against) and voucher_type in ['Sales Invoice', 'Delivery Note']:
|
||||||
|
rate = frappe.db.get_value(f'{voucher_type} Item', voucher_detail_no, 'incoming_rate')
|
||||||
|
|
||||||
|
if not rate and sle:
|
||||||
|
rate = get_incoming_rate({
|
||||||
"item_code": sle.item_code,
|
"item_code": sle.item_code,
|
||||||
"warehouse": sle.warehouse,
|
"warehouse": sle.warehouse,
|
||||||
"posting_date": sle.get('posting_date'),
|
"posting_date": sle.get('posting_date'),
|
||||||
@@ -407,17 +421,7 @@ def get_rate_for_return(voucher_type, voucher_no, item_code, return_against=None
|
|||||||
"voucher_no": sle.voucher_no
|
"voucher_no": sle.voucher_no
|
||||||
}, raise_error_if_no_rate=False)
|
}, raise_error_if_no_rate=False)
|
||||||
|
|
||||||
return_against_item_field = get_return_against_item_fields(voucher_type)
|
return rate
|
||||||
|
|
||||||
filters = get_filters(voucher_type, voucher_no, voucher_detail_no,
|
|
||||||
return_against, item_code, return_against_item_field, item_row)
|
|
||||||
|
|
||||||
if voucher_type in ("Purchase Receipt", "Purchase Invoice"):
|
|
||||||
select_field = "incoming_rate"
|
|
||||||
else:
|
|
||||||
select_field = "abs(stock_value_difference / actual_qty)"
|
|
||||||
|
|
||||||
return flt(frappe.db.get_value("Stock Ledger Entry", filters, select_field))
|
|
||||||
|
|
||||||
def get_return_against_item_fields(voucher_type):
|
def get_return_against_item_fields(voucher_type):
|
||||||
return_against_item_fields = {
|
return_against_item_fields = {
|
||||||
|
|||||||
@@ -362,7 +362,7 @@ class SellingController(StockController):
|
|||||||
sales_order.update_reserved_qty(so_item_rows)
|
sales_order.update_reserved_qty(so_item_rows)
|
||||||
|
|
||||||
def set_incoming_rate(self):
|
def set_incoming_rate(self):
|
||||||
if self.doctype not in ("Delivery Note", "Sales Invoice", "Sales Order"):
|
if self.doctype not in ("Delivery Note", "Sales Invoice"):
|
||||||
return
|
return
|
||||||
|
|
||||||
items = self.get("items") + (self.get("packed_items") or [])
|
items = self.get("items") + (self.get("packed_items") or [])
|
||||||
@@ -371,6 +371,7 @@ class SellingController(StockController):
|
|||||||
# Get incoming rate based on original item cost based on valuation method
|
# Get incoming rate based on original item cost based on valuation method
|
||||||
qty = flt(d.get('stock_qty') or d.get('actual_qty'))
|
qty = flt(d.get('stock_qty') or d.get('actual_qty'))
|
||||||
|
|
||||||
|
if not d.incoming_rate:
|
||||||
d.incoming_rate = get_incoming_rate({
|
d.incoming_rate = get_incoming_rate({
|
||||||
"item_code": d.item_code,
|
"item_code": d.item_code,
|
||||||
"warehouse": d.warehouse,
|
"warehouse": d.warehouse,
|
||||||
|
|||||||
@@ -46,13 +46,13 @@
|
|||||||
{
|
{
|
||||||
"fieldname": "visited",
|
"fieldname": "visited",
|
||||||
"fieldtype": "Int",
|
"fieldtype": "Int",
|
||||||
"label": "Visited yet",
|
"label": "Visits Completed",
|
||||||
"read_only": 1
|
"read_only": 1
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"fieldname": "valid_till",
|
"fieldname": "valid_till",
|
||||||
"fieldtype": "Date",
|
"fieldtype": "Date",
|
||||||
"label": "Valid till",
|
"label": "Valid Till",
|
||||||
"read_only": 1
|
"read_only": 1
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@@ -106,7 +106,7 @@
|
|||||||
],
|
],
|
||||||
"in_create": 1,
|
"in_create": 1,
|
||||||
"links": [],
|
"links": [],
|
||||||
"modified": "2020-03-17 20:25:06.487418",
|
"modified": "2021-08-26 10:51:05.609349",
|
||||||
"modified_by": "Administrator",
|
"modified_by": "Administrator",
|
||||||
"module": "Healthcare",
|
"module": "Healthcare",
|
||||||
"name": "Fee Validity",
|
"name": "Fee Validity",
|
||||||
|
|||||||
@@ -11,7 +11,6 @@ import datetime
|
|||||||
class FeeValidity(Document):
|
class FeeValidity(Document):
|
||||||
def validate(self):
|
def validate(self):
|
||||||
self.update_status()
|
self.update_status()
|
||||||
self.set_start_date()
|
|
||||||
|
|
||||||
def update_status(self):
|
def update_status(self):
|
||||||
if self.visited >= self.max_visits:
|
if self.visited >= self.max_visits:
|
||||||
@@ -19,13 +18,6 @@ class FeeValidity(Document):
|
|||||||
else:
|
else:
|
||||||
self.status = 'Pending'
|
self.status = 'Pending'
|
||||||
|
|
||||||
def set_start_date(self):
|
|
||||||
self.start_date = getdate()
|
|
||||||
for appointment in self.ref_appointments:
|
|
||||||
appointment_date = frappe.db.get_value('Patient Appointment', appointment.appointment, 'appointment_date')
|
|
||||||
if getdate(appointment_date) < self.start_date:
|
|
||||||
self.start_date = getdate(appointment_date)
|
|
||||||
|
|
||||||
|
|
||||||
def create_fee_validity(appointment):
|
def create_fee_validity(appointment):
|
||||||
if not check_is_new_patient(appointment):
|
if not check_is_new_patient(appointment):
|
||||||
@@ -36,11 +28,9 @@ def create_fee_validity(appointment):
|
|||||||
fee_validity.patient = appointment.patient
|
fee_validity.patient = appointment.patient
|
||||||
fee_validity.max_visits = frappe.db.get_single_value('Healthcare Settings', 'max_visits') or 1
|
fee_validity.max_visits = frappe.db.get_single_value('Healthcare Settings', 'max_visits') or 1
|
||||||
valid_days = frappe.db.get_single_value('Healthcare Settings', 'valid_days') or 1
|
valid_days = frappe.db.get_single_value('Healthcare Settings', 'valid_days') or 1
|
||||||
fee_validity.visited = 1
|
fee_validity.visited = 0
|
||||||
|
fee_validity.start_date = getdate(appointment.appointment_date)
|
||||||
fee_validity.valid_till = getdate(appointment.appointment_date) + datetime.timedelta(days=int(valid_days))
|
fee_validity.valid_till = getdate(appointment.appointment_date) + datetime.timedelta(days=int(valid_days))
|
||||||
fee_validity.append('ref_appointments', {
|
|
||||||
'appointment': appointment.name
|
|
||||||
})
|
|
||||||
fee_validity.save(ignore_permissions=True)
|
fee_validity.save(ignore_permissions=True)
|
||||||
return fee_validity
|
return fee_validity
|
||||||
|
|
||||||
|
|||||||
@@ -22,14 +22,14 @@ class TestFeeValidity(unittest.TestCase):
|
|||||||
item = create_healthcare_service_items()
|
item = create_healthcare_service_items()
|
||||||
healthcare_settings = frappe.get_single("Healthcare Settings")
|
healthcare_settings = frappe.get_single("Healthcare Settings")
|
||||||
healthcare_settings.enable_free_follow_ups = 1
|
healthcare_settings.enable_free_follow_ups = 1
|
||||||
healthcare_settings.max_visits = 2
|
healthcare_settings.max_visits = 1
|
||||||
healthcare_settings.valid_days = 7
|
healthcare_settings.valid_days = 7
|
||||||
healthcare_settings.automate_appointment_invoicing = 1
|
healthcare_settings.automate_appointment_invoicing = 1
|
||||||
healthcare_settings.op_consulting_charge_item = item
|
healthcare_settings.op_consulting_charge_item = item
|
||||||
healthcare_settings.save(ignore_permissions=True)
|
healthcare_settings.save(ignore_permissions=True)
|
||||||
patient, practitioner = create_healthcare_docs()
|
patient, practitioner = create_healthcare_docs()
|
||||||
|
|
||||||
# For first appointment, invoice is generated
|
# For first appointment, invoice is generated. First appointment not considered in fee validity
|
||||||
appointment = create_appointment(patient, practitioner, nowdate())
|
appointment = create_appointment(patient, practitioner, nowdate())
|
||||||
invoiced = frappe.db.get_value("Patient Appointment", appointment.name, "invoiced")
|
invoiced = frappe.db.get_value("Patient Appointment", appointment.name, "invoiced")
|
||||||
self.assertEqual(invoiced, 1)
|
self.assertEqual(invoiced, 1)
|
||||||
|
|||||||
@@ -137,9 +137,13 @@ class PatientAppointment(Document):
|
|||||||
frappe.db.set_value('Patient Appointment', self.name, 'notes', comments)
|
frappe.db.set_value('Patient Appointment', self.name, 'notes', comments)
|
||||||
|
|
||||||
def update_fee_validity(self):
|
def update_fee_validity(self):
|
||||||
|
if not frappe.db.get_single_value('Healthcare Settings', 'enable_free_follow_ups'):
|
||||||
|
return
|
||||||
|
|
||||||
fee_validity = manage_fee_validity(self)
|
fee_validity = manage_fee_validity(self)
|
||||||
if fee_validity:
|
if fee_validity:
|
||||||
frappe.msgprint(_('{0} has fee validity till {1}').format(self.patient, fee_validity.valid_till))
|
frappe.msgprint(_('{0}: {1} has fee validity till {2}').format(self.patient,
|
||||||
|
frappe.bold(self.patient_name), fee_validity.valid_till))
|
||||||
|
|
||||||
@frappe.whitelist()
|
@frappe.whitelist()
|
||||||
def get_therapy_types(self):
|
def get_therapy_types(self):
|
||||||
|
|||||||
@@ -110,18 +110,21 @@ class TestPatientAppointment(unittest.TestCase):
|
|||||||
patient, practitioner = create_healthcare_docs()
|
patient, practitioner = create_healthcare_docs()
|
||||||
frappe.db.set_value('Healthcare Settings', None, 'enable_free_follow_ups', 1)
|
frappe.db.set_value('Healthcare Settings', None, 'enable_free_follow_ups', 1)
|
||||||
appointment = create_appointment(patient, practitioner, nowdate())
|
appointment = create_appointment(patient, practitioner, nowdate())
|
||||||
fee_validity = frappe.db.get_value('Fee Validity Reference', {'appointment': appointment.name}, 'parent')
|
fee_validity = frappe.db.get_value('Fee Validity', {'patient': patient, 'practitioner': practitioner})
|
||||||
# fee validity created
|
# fee validity created
|
||||||
self.assertTrue(fee_validity)
|
self.assertTrue(fee_validity)
|
||||||
|
|
||||||
visited = frappe.db.get_value('Fee Validity', fee_validity, 'visited')
|
# first follow up appointment
|
||||||
|
appointment = create_appointment(patient, practitioner, add_days(nowdate(), 1))
|
||||||
|
self.assertEqual(frappe.db.get_value('Fee Validity', fee_validity, 'visited'), 1)
|
||||||
|
|
||||||
update_status(appointment.name, 'Cancelled')
|
update_status(appointment.name, 'Cancelled')
|
||||||
# check fee validity updated
|
# check fee validity updated
|
||||||
self.assertEqual(frappe.db.get_value('Fee Validity', fee_validity, 'visited'), visited - 1)
|
self.assertEqual(frappe.db.get_value('Fee Validity', fee_validity, 'visited'), 0)
|
||||||
|
|
||||||
frappe.db.set_value('Healthcare Settings', None, 'enable_free_follow_ups', 0)
|
frappe.db.set_value('Healthcare Settings', None, 'enable_free_follow_ups', 0)
|
||||||
frappe.db.set_value('Healthcare Settings', None, 'automate_appointment_invoicing', 1)
|
frappe.db.set_value('Healthcare Settings', None, 'automate_appointment_invoicing', 1)
|
||||||
appointment = create_appointment(patient, practitioner, nowdate(), invoice=1)
|
appointment = create_appointment(patient, practitioner, add_days(nowdate(), 1), invoice=1)
|
||||||
update_status(appointment.name, 'Cancelled')
|
update_status(appointment.name, 'Cancelled')
|
||||||
# check invoice cancelled
|
# check invoice cancelled
|
||||||
sales_invoice_name = frappe.db.get_value('Sales Invoice Item', {'reference_dn': appointment.name}, 'parent')
|
sales_invoice_name = frappe.db.get_value('Sales Invoice Item', {'reference_dn': appointment.name}, 'parent')
|
||||||
|
|||||||
@@ -0,0 +1,193 @@
|
|||||||
|
# Copyright (c) 2021, Frappe Technologies Pvt. Ltd. and contributors
|
||||||
|
# For license information, please see license.txt
|
||||||
|
|
||||||
|
from __future__ import unicode_literals
|
||||||
|
import frappe
|
||||||
|
from unittest import TestCase
|
||||||
|
from frappe.utils import today
|
||||||
|
|
||||||
|
from erpnext.accounts.doctype.account.test_account import create_account
|
||||||
|
from erpnext.accounts.doctype.sales_invoice.test_sales_invoice import create_sales_invoice
|
||||||
|
from erpnext.accounts.doctype.purchase_invoice.test_purchase_invoice import make_purchase_invoice
|
||||||
|
|
||||||
|
from erpnext.regional.report.vat_audit_report.vat_audit_report import execute
|
||||||
|
|
||||||
|
class TestVATAuditReport(TestCase):
|
||||||
|
def setUp(self):
|
||||||
|
frappe.set_user("Administrator")
|
||||||
|
make_company("_Test Company SA VAT", "_TCSV")
|
||||||
|
|
||||||
|
create_account(account_name="VAT - 0%", account_type="Tax",
|
||||||
|
parent_account="Duties and Taxes - _TCSV", company="_Test Company SA VAT")
|
||||||
|
create_account(account_name="VAT - 15%", account_type="Tax",
|
||||||
|
parent_account="Duties and Taxes - _TCSV", company="_Test Company SA VAT")
|
||||||
|
set_sa_vat_accounts()
|
||||||
|
|
||||||
|
make_item("_Test SA VAT Item")
|
||||||
|
make_item("_Test SA VAT Zero Rated Item", properties = {"is_zero_rated": 1})
|
||||||
|
|
||||||
|
make_customer()
|
||||||
|
make_supplier()
|
||||||
|
|
||||||
|
make_sales_invoices()
|
||||||
|
create_purchase_invoices()
|
||||||
|
|
||||||
|
def tearDown(self):
|
||||||
|
frappe.db.sql("delete from `tabSales Invoice` where company='_Test Company SA VAT'")
|
||||||
|
frappe.db.sql("delete from `tabPurchase Invoice` where company='_Test Company SA VAT'")
|
||||||
|
|
||||||
|
def test_vat_audit_report(self):
|
||||||
|
filters = {
|
||||||
|
"company": "_Test Company SA VAT",
|
||||||
|
"from_date": today(),
|
||||||
|
"to_date": today()
|
||||||
|
}
|
||||||
|
columns, data = execute(filters)
|
||||||
|
total_tax_amount = 0
|
||||||
|
total_row_tax = 0
|
||||||
|
for row in data:
|
||||||
|
keys = row.keys()
|
||||||
|
# skips total row tax_amount in if.. and skips section header in elif..
|
||||||
|
if 'voucher_no' in keys:
|
||||||
|
total_tax_amount = total_tax_amount + row['tax_amount']
|
||||||
|
elif 'tax_amount' in keys:
|
||||||
|
total_row_tax = total_row_tax + row['tax_amount']
|
||||||
|
|
||||||
|
self.assertEqual(total_tax_amount, total_row_tax)
|
||||||
|
|
||||||
|
def make_company(company_name, abbr):
|
||||||
|
if not frappe.db.exists("Company", company_name):
|
||||||
|
company = frappe.get_doc({
|
||||||
|
"doctype": "Company",
|
||||||
|
"company_name": company_name,
|
||||||
|
"abbr": abbr,
|
||||||
|
"default_currency": "ZAR",
|
||||||
|
"country": "South Africa",
|
||||||
|
"create_chart_of_accounts_based_on": "Standard Template"
|
||||||
|
})
|
||||||
|
company.insert()
|
||||||
|
else:
|
||||||
|
company = frappe.get_doc("Company", company_name)
|
||||||
|
|
||||||
|
company.create_default_warehouses()
|
||||||
|
|
||||||
|
if not frappe.db.get_value("Cost Center", {"is_group": 0, "company": company.name}):
|
||||||
|
company.create_default_cost_center()
|
||||||
|
|
||||||
|
company.save()
|
||||||
|
|
||||||
|
return company
|
||||||
|
|
||||||
|
def set_sa_vat_accounts():
|
||||||
|
if not frappe.db.exists("South Africa VAT Settings", "_Test Company SA VAT"):
|
||||||
|
vat_accounts = frappe.get_all(
|
||||||
|
"Account",
|
||||||
|
fields=["name"],
|
||||||
|
filters = {
|
||||||
|
"company": "_Test Company SA VAT",
|
||||||
|
"is_group": 0,
|
||||||
|
"account_type": "Tax"
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
sa_vat_accounts = []
|
||||||
|
for account in vat_accounts:
|
||||||
|
sa_vat_accounts.append({
|
||||||
|
"doctype": "South Africa VAT Account",
|
||||||
|
"account": account.name
|
||||||
|
})
|
||||||
|
|
||||||
|
frappe.get_doc({
|
||||||
|
"company": "_Test Company SA VAT",
|
||||||
|
"vat_accounts": sa_vat_accounts,
|
||||||
|
"doctype": "South Africa VAT Settings",
|
||||||
|
}).insert()
|
||||||
|
|
||||||
|
def make_customer():
|
||||||
|
if not frappe.db.exists("Customer", "_Test SA Customer"):
|
||||||
|
frappe.get_doc({
|
||||||
|
"doctype": "Customer",
|
||||||
|
"customer_name": "_Test SA Customer",
|
||||||
|
"customer_type": "Company",
|
||||||
|
}).insert()
|
||||||
|
|
||||||
|
def make_supplier():
|
||||||
|
if not frappe.db.exists("Supplier", "_Test SA Supplier"):
|
||||||
|
frappe.get_doc({
|
||||||
|
"doctype": "Supplier",
|
||||||
|
"supplier_name": "_Test SA Supplier",
|
||||||
|
"supplier_type": "Company",
|
||||||
|
"supplier_group":"All Supplier Groups"
|
||||||
|
}).insert()
|
||||||
|
|
||||||
|
def make_item(item_code, properties=None):
|
||||||
|
if not frappe.db.exists("Item", item_code):
|
||||||
|
item = frappe.get_doc({
|
||||||
|
"doctype": "Item",
|
||||||
|
"item_code": item_code,
|
||||||
|
"item_name": item_code,
|
||||||
|
"description": item_code,
|
||||||
|
"item_group": "Products"
|
||||||
|
})
|
||||||
|
|
||||||
|
if properties:
|
||||||
|
item.update(properties)
|
||||||
|
|
||||||
|
item.insert()
|
||||||
|
|
||||||
|
def make_sales_invoices():
|
||||||
|
def make_sales_invoices_wrapper(item, rate, tax_account, tax_rate, tax=True):
|
||||||
|
si = create_sales_invoice(
|
||||||
|
company="_Test Company SA VAT",
|
||||||
|
customer = "_Test SA Customer",
|
||||||
|
currency = "ZAR",
|
||||||
|
item=item,
|
||||||
|
rate=rate,
|
||||||
|
warehouse = "Finished Goods - _TCSV",
|
||||||
|
debit_to = "Debtors - _TCSV",
|
||||||
|
income_account = "Sales - _TCSV",
|
||||||
|
expense_account = "Cost of Goods Sold - _TCSV",
|
||||||
|
cost_center = "Main - _TCSV",
|
||||||
|
do_not_save=1
|
||||||
|
)
|
||||||
|
if tax:
|
||||||
|
si.append("taxes", {
|
||||||
|
"charge_type": "On Net Total",
|
||||||
|
"account_head": tax_account,
|
||||||
|
"cost_center": "Main - _TCSV",
|
||||||
|
"description": "VAT 15% @ 15.0",
|
||||||
|
"rate": tax_rate
|
||||||
|
})
|
||||||
|
|
||||||
|
si.submit()
|
||||||
|
|
||||||
|
test_item = "_Test SA VAT Item"
|
||||||
|
test_zero_rated_item = "_Test SA VAT Zero Rated Item"
|
||||||
|
|
||||||
|
make_sales_invoices_wrapper(test_item, 100.0, "VAT - 15% - _TCSV", 15.0)
|
||||||
|
make_sales_invoices_wrapper(test_zero_rated_item, 100.0, "VAT - 0% - _TCSV", 0.0)
|
||||||
|
|
||||||
|
def create_purchase_invoices():
|
||||||
|
pi = make_purchase_invoice(
|
||||||
|
company = "_Test Company SA VAT",
|
||||||
|
supplier = "_Test SA Supplier",
|
||||||
|
supplier_warehouse = "Finished Goods - _TCSV",
|
||||||
|
warehouse = "Finished Goods - _TCSV",
|
||||||
|
currency = "ZAR",
|
||||||
|
cost_center = "Main - _TCSV",
|
||||||
|
expense_account = "Cost of Goods Sold - _TCSV",
|
||||||
|
item = "_Test SA VAT Item",
|
||||||
|
qty = 1,
|
||||||
|
rate = 100,
|
||||||
|
uom = "Nos",
|
||||||
|
do_not_save = 1
|
||||||
|
)
|
||||||
|
pi.append("taxes", {
|
||||||
|
"charge_type": "On Net Total",
|
||||||
|
"account_head": "VAT - 15% - _TCSV",
|
||||||
|
"cost_center": "Main - _TCSV",
|
||||||
|
"description": "VAT 15% @ 15.0",
|
||||||
|
"rate": 15.0
|
||||||
|
})
|
||||||
|
|
||||||
|
pi.submit()
|
||||||
@@ -1,11 +1,11 @@
|
|||||||
# Copyright (c) 2013, Frappe Technologies Pvt. Ltd. and contributors
|
# Copyright (c) 2021, Frappe Technologies Pvt. Ltd. and contributors
|
||||||
# For license information, please see license.txt
|
# For license information, please see license.txt
|
||||||
|
|
||||||
from __future__ import unicode_literals
|
from __future__ import unicode_literals
|
||||||
import frappe
|
import frappe
|
||||||
import json
|
import json
|
||||||
from frappe import _
|
from frappe import _
|
||||||
from frappe.utils import formatdate
|
from frappe.utils import formatdate, get_link_to_form
|
||||||
|
|
||||||
def execute(filters=None):
|
def execute(filters=None):
|
||||||
return VATAuditReport(filters).run()
|
return VATAuditReport(filters).run()
|
||||||
@@ -42,7 +42,8 @@ class VATAuditReport(object):
|
|||||||
self.sa_vat_accounts = frappe.get_list("South Africa VAT Account",
|
self.sa_vat_accounts = frappe.get_list("South Africa VAT Account",
|
||||||
filters = {"parent": self.filters.company}, pluck="account")
|
filters = {"parent": self.filters.company}, pluck="account")
|
||||||
if not self.sa_vat_accounts and not frappe.flags.in_test and not frappe.flags.in_migrate:
|
if not self.sa_vat_accounts and not frappe.flags.in_test and not frappe.flags.in_migrate:
|
||||||
frappe.throw(_("Please set VAT Accounts in South Africa VAT Settings"))
|
link_to_settings = get_link_to_form("South Africa VAT Settings", "", label="South Africa VAT Settings")
|
||||||
|
frappe.throw(_("Please set VAT Accounts in {0}").format(link_to_settings))
|
||||||
|
|
||||||
def get_invoice_data(self, doctype):
|
def get_invoice_data(self, doctype):
|
||||||
conditions = self.get_conditions()
|
conditions = self.get_conditions()
|
||||||
@@ -69,7 +70,7 @@ class VATAuditReport(object):
|
|||||||
|
|
||||||
items = frappe.db.sql("""
|
items = frappe.db.sql("""
|
||||||
SELECT
|
SELECT
|
||||||
item_code, parent, taxable_value, base_net_amount, is_zero_rated
|
item_code, parent, base_net_amount, is_zero_rated
|
||||||
FROM
|
FROM
|
||||||
`tab%s Item`
|
`tab%s Item`
|
||||||
WHERE
|
WHERE
|
||||||
@@ -79,7 +80,7 @@ class VATAuditReport(object):
|
|||||||
if d.item_code not in self.invoice_items.get(d.parent, {}):
|
if d.item_code not in self.invoice_items.get(d.parent, {}):
|
||||||
self.invoice_items.setdefault(d.parent, {}).setdefault(d.item_code, {
|
self.invoice_items.setdefault(d.parent, {}).setdefault(d.item_code, {
|
||||||
'net_amount': 0.0})
|
'net_amount': 0.0})
|
||||||
self.invoice_items[d.parent][d.item_code]['net_amount'] += d.get('taxable_value', 0) or d.get('base_net_amount', 0)
|
self.invoice_items[d.parent][d.item_code]['net_amount'] += d.get('base_net_amount', 0)
|
||||||
self.invoice_items[d.parent][d.item_code]['is_zero_rated'] = d.is_zero_rated
|
self.invoice_items[d.parent][d.item_code]['is_zero_rated'] = d.is_zero_rated
|
||||||
|
|
||||||
def get_items_based_on_tax_rate(self, doctype):
|
def get_items_based_on_tax_rate(self, doctype):
|
||||||
|
|||||||
@@ -324,6 +324,7 @@ class update_entries_after(object):
|
|||||||
where
|
where
|
||||||
item_code = %(item_code)s
|
item_code = %(item_code)s
|
||||||
and warehouse = %(warehouse)s
|
and warehouse = %(warehouse)s
|
||||||
|
and is_cancelled = 0
|
||||||
and timestamp(posting_date, time_format(posting_time, %(time_format)s)) = timestamp(%(posting_date)s, time_format(%(posting_time)s, %(time_format)s))
|
and timestamp(posting_date, time_format(posting_time, %(time_format)s)) = timestamp(%(posting_date)s, time_format(%(posting_time)s, %(time_format)s))
|
||||||
|
|
||||||
order by
|
order by
|
||||||
|
|||||||
Reference in New Issue
Block a user