Merge branch 'develop' into club-mr-column

This commit is contained in:
Marica 2020-07-20 16:07:10 +05:30 committed by GitHub
commit 8ec4198af2
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
59 changed files with 659 additions and 701 deletions

View File

@ -19,7 +19,6 @@
"unlink_payment_on_cancellation_of_invoice", "unlink_payment_on_cancellation_of_invoice",
"unlink_advance_payment_on_cancelation_of_order", "unlink_advance_payment_on_cancelation_of_order",
"book_asset_depreciation_entry_automatically", "book_asset_depreciation_entry_automatically",
"allow_cost_center_in_entry_of_bs_account",
"add_taxes_from_item_tax_template", "add_taxes_from_item_tax_template",
"automatically_fetch_payment_terms", "automatically_fetch_payment_terms",
"deferred_accounting_settings_section", "deferred_accounting_settings_section",
@ -113,12 +112,6 @@
"fieldtype": "Check", "fieldtype": "Check",
"label": "Book Asset Depreciation Entry Automatically" "label": "Book Asset Depreciation Entry Automatically"
}, },
{
"default": "0",
"fieldname": "allow_cost_center_in_entry_of_bs_account",
"fieldtype": "Check",
"label": "Allow Cost Center In Entry of Balance Sheet Account"
},
{ {
"default": "1", "default": "1",
"fieldname": "add_taxes_from_item_tax_template", "fieldname": "add_taxes_from_item_tax_template",

View File

@ -20,7 +20,6 @@ class AccountsSettings(Document):
self.validate_stale_days() self.validate_stale_days()
self.enable_payment_schedule_in_print() self.enable_payment_schedule_in_print()
self.enable_fields_for_cost_center_settings()
def validate_stale_days(self): def validate_stale_days(self):
if not self.allow_stale and cint(self.stale_days) <= 0: if not self.allow_stale and cint(self.stale_days) <= 0:
@ -33,8 +32,3 @@ class AccountsSettings(Document):
for doctype in ("Sales Order", "Sales Invoice", "Purchase Order", "Purchase Invoice"): for doctype in ("Sales Order", "Sales Invoice", "Purchase Order", "Purchase Invoice"):
make_property_setter(doctype, "due_date", "print_hide", show_in_print, "Check") make_property_setter(doctype, "due_date", "print_hide", show_in_print, "Check")
make_property_setter(doctype, "payment_schedule", "print_hide", 0 if show_in_print else 1, "Check") make_property_setter(doctype, "payment_schedule", "print_hide", 0 if show_in_print else 1, "Check")
def enable_fields_for_cost_center_settings(self):
show_field = 0 if cint(self.allow_cost_center_in_entry_of_bs_account) else 1
for doctype in ("Sales Invoice", "Purchase Invoice", "Payment Entry"):
make_property_setter(doctype, "cost_center", "hidden", show_field, "Check")

View File

@ -72,12 +72,6 @@ class GLEntry(Document):
if not self.cost_center and self.voucher_type != 'Period Closing Voucher': if not self.cost_center and self.voucher_type != 'Period Closing Voucher':
frappe.throw(_("{0} {1}: Cost Center is required for 'Profit and Loss' account {2}. Please set up a default Cost Center for the Company.") frappe.throw(_("{0} {1}: Cost Center is required for 'Profit and Loss' account {2}. Please set up a default Cost Center for the Company.")
.format(self.voucher_type, self.voucher_no, self.account)) .format(self.voucher_type, self.voucher_no, self.account))
else:
from erpnext.accounts.utils import get_allow_cost_center_in_entry_of_bs_account
if not get_allow_cost_center_in_entry_of_bs_account() and self.cost_center:
self.cost_center = None
if self.project:
self.project = None
def validate_dimensions_for_pl_and_bs(self): def validate_dimensions_for_pl_and_bs(self):

View File

@ -3,7 +3,7 @@
# 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, json import frappe, json, erpnext
from frappe import _ from frappe import _
from frappe.utils import flt, getdate, nowdate, add_days from frappe.utils import flt, getdate, nowdate, add_days
from erpnext.controllers.accounts_controller import AccountsController from erpnext.controllers.accounts_controller import AccountsController
@ -134,16 +134,19 @@ class InvoiceDiscounting(AccountsController):
je.append("accounts", { je.append("accounts", {
"account": self.bank_account, "account": self.bank_account,
"debit_in_account_currency": flt(self.total_amount) - flt(self.bank_charges), "debit_in_account_currency": flt(self.total_amount) - flt(self.bank_charges),
"cost_center": erpnext.get_default_cost_center(self.company)
}) })
je.append("accounts", { je.append("accounts", {
"account": self.bank_charges_account, "account": self.bank_charges_account,
"debit_in_account_currency": flt(self.bank_charges) "debit_in_account_currency": flt(self.bank_charges),
"cost_center": erpnext.get_default_cost_center(self.company)
}) })
je.append("accounts", { je.append("accounts", {
"account": self.short_term_loan, "account": self.short_term_loan,
"credit_in_account_currency": flt(self.total_amount), "credit_in_account_currency": flt(self.total_amount),
"cost_center": erpnext.get_default_cost_center(self.company),
"reference_type": "Invoice Discounting", "reference_type": "Invoice Discounting",
"reference_name": self.name "reference_name": self.name
}) })
@ -151,6 +154,7 @@ class InvoiceDiscounting(AccountsController):
je.append("accounts", { je.append("accounts", {
"account": self.accounts_receivable_discounted, "account": self.accounts_receivable_discounted,
"debit_in_account_currency": flt(d.outstanding_amount), "debit_in_account_currency": flt(d.outstanding_amount),
"cost_center": erpnext.get_default_cost_center(self.company),
"reference_type": "Invoice Discounting", "reference_type": "Invoice Discounting",
"reference_name": self.name, "reference_name": self.name,
"party_type": "Customer", "party_type": "Customer",
@ -160,6 +164,7 @@ class InvoiceDiscounting(AccountsController):
je.append("accounts", { je.append("accounts", {
"account": self.accounts_receivable_credit, "account": self.accounts_receivable_credit,
"credit_in_account_currency": flt(d.outstanding_amount), "credit_in_account_currency": flt(d.outstanding_amount),
"cost_center": erpnext.get_default_cost_center(self.company),
"reference_type": "Invoice Discounting", "reference_type": "Invoice Discounting",
"reference_name": self.name, "reference_name": self.name,
"party_type": "Customer", "party_type": "Customer",
@ -177,13 +182,15 @@ class InvoiceDiscounting(AccountsController):
je.append("accounts", { je.append("accounts", {
"account": self.short_term_loan, "account": self.short_term_loan,
"debit_in_account_currency": flt(self.total_amount), "debit_in_account_currency": flt(self.total_amount),
"cost_center": erpnext.get_default_cost_center(self.company),
"reference_type": "Invoice Discounting", "reference_type": "Invoice Discounting",
"reference_name": self.name, "reference_name": self.name,
}) })
je.append("accounts", { je.append("accounts", {
"account": self.bank_account, "account": self.bank_account,
"credit_in_account_currency": flt(self.total_amount) "credit_in_account_currency": flt(self.total_amount),
"cost_center": erpnext.get_default_cost_center(self.company)
}) })
if getdate(self.loan_end_date) > getdate(nowdate()): if getdate(self.loan_end_date) > getdate(nowdate()):
@ -193,6 +200,7 @@ class InvoiceDiscounting(AccountsController):
je.append("accounts", { je.append("accounts", {
"account": self.accounts_receivable_discounted, "account": self.accounts_receivable_discounted,
"credit_in_account_currency": flt(outstanding_amount), "credit_in_account_currency": flt(outstanding_amount),
"cost_center": erpnext.get_default_cost_center(self.company),
"reference_type": "Invoice Discounting", "reference_type": "Invoice Discounting",
"reference_name": self.name, "reference_name": self.name,
"party_type": "Customer", "party_type": "Customer",
@ -202,6 +210,7 @@ class InvoiceDiscounting(AccountsController):
je.append("accounts", { je.append("accounts", {
"account": self.accounts_receivable_unpaid, "account": self.accounts_receivable_unpaid,
"debit_in_account_currency": flt(outstanding_amount), "debit_in_account_currency": flt(outstanding_amount),
"cost_center": erpnext.get_default_cost_center(self.company),
"reference_type": "Invoice Discounting", "reference_type": "Invoice Discounting",
"reference_name": self.name, "reference_name": self.name,
"party_type": "Customer", "party_type": "Customer",

View File

@ -204,11 +204,8 @@ class TestJournalEntry(unittest.TestCase):
self.assertEqual(jv.inter_company_journal_entry_reference, "") self.assertEqual(jv.inter_company_journal_entry_reference, "")
self.assertEqual(jv1.inter_company_journal_entry_reference, "") self.assertEqual(jv1.inter_company_journal_entry_reference, "")
def test_jv_for_enable_allow_cost_center_in_entry_of_bs_account(self): def test_jv_with_cost_centre(self):
from erpnext.accounts.doctype.cost_center.test_cost_center import create_cost_center from erpnext.accounts.doctype.cost_center.test_cost_center import create_cost_center
accounts_settings = frappe.get_doc('Accounts Settings', 'Accounts Settings')
accounts_settings.allow_cost_center_in_entry_of_bs_account = 1
accounts_settings.save()
cost_center = "_Test Cost Center for BS Account - _TC" cost_center = "_Test Cost Center for BS Account - _TC"
create_cost_center(cost_center_name="_Test Cost Center for BS Account", company="_Test Company") create_cost_center(cost_center_name="_Test Cost Center for BS Account", company="_Test Company")
jv = make_journal_entry("_Test Cash - _TC", "_Test Bank - _TC", 100, cost_center = cost_center, save=False) jv = make_journal_entry("_Test Cash - _TC", "_Test Bank - _TC", 100, cost_center = cost_center, save=False)
@ -237,15 +234,45 @@ class TestJournalEntry(unittest.TestCase):
for gle in gl_entries: for gle in gl_entries:
self.assertEqual(expected_values[gle.account]["cost_center"], gle.cost_center) self.assertEqual(expected_values[gle.account]["cost_center"], gle.cost_center)
accounts_settings.allow_cost_center_in_entry_of_bs_account = 0 def test_jv_with_project(self):
accounts_settings.save() from erpnext.projects.doctype.project.test_project import make_project
project = make_project({
'project_name': 'Journal Entry Project',
'project_template_name': 'Test Project Template',
'start_date': '2020-01-01'
})
def test_jv_account_and_party_balance_for_enable_allow_cost_center_in_entry_of_bs_account(self): jv = make_journal_entry("_Test Cash - _TC", "_Test Bank - _TC", 100, save=False)
for d in jv.accounts:
d.project = project.project_name
jv.voucher_type = "Bank Entry"
jv.multi_currency = 0
jv.cheque_no = "112233"
jv.cheque_date = nowdate()
jv.insert()
jv.submit()
expected_values = {
"_Test Cash - _TC": {
"project": project.project_name
},
"_Test Bank - _TC": {
"project": project.project_name
}
}
gl_entries = frappe.db.sql("""select account, project, debit, credit
from `tabGL Entry` where voucher_type='Journal Entry' and voucher_no=%s
order by account asc""", jv.name, as_dict=1)
self.assertTrue(gl_entries)
for gle in gl_entries:
self.assertEqual(expected_values[gle.account]["project"], gle.project)
def test_jv_account_and_party_balance_with_cost_centre(self):
from erpnext.accounts.doctype.cost_center.test_cost_center import create_cost_center from erpnext.accounts.doctype.cost_center.test_cost_center import create_cost_center
from erpnext.accounts.utils import get_balance_on from erpnext.accounts.utils import get_balance_on
accounts_settings = frappe.get_doc('Accounts Settings', 'Accounts Settings')
accounts_settings.allow_cost_center_in_entry_of_bs_account = 1
accounts_settings.save()
cost_center = "_Test Cost Center for BS Account - _TC" cost_center = "_Test Cost Center for BS Account - _TC"
create_cost_center(cost_center_name="_Test Cost Center for BS Account", company="_Test Company") create_cost_center(cost_center_name="_Test Cost Center for BS Account", company="_Test Company")
jv = make_journal_entry("_Test Cash - _TC", "_Test Bank - _TC", 100, cost_center = cost_center, save=False) jv = make_journal_entry("_Test Cash - _TC", "_Test Bank - _TC", 100, cost_center = cost_center, save=False)
@ -261,9 +288,6 @@ class TestJournalEntry(unittest.TestCase):
account_balance = get_balance_on(account="_Test Bank - _TC", cost_center=cost_center) account_balance = get_balance_on(account="_Test Bank - _TC", cost_center=cost_center)
self.assertEqual(expected_account_balance, account_balance) self.assertEqual(expected_account_balance, account_balance)
accounts_settings.allow_cost_center_in_entry_of_bs_account = 0
accounts_settings.save()
def make_journal_entry(account1, account2, amount, cost_center=None, posting_date=None, exchange_rate=1, save=True, submit=False, project=None): def make_journal_entry(account1, account2, amount, cost_center=None, posting_date=None, exchange_rate=1, save=True, submit=False, project=None):
if not cost_center: if not cost_center:
cost_center = "_Test Cost Center - _TC" cost_center = "_Test Cost Center - _TC"

View File

@ -6,7 +6,7 @@ from __future__ import unicode_literals
import frappe, erpnext, json import frappe, erpnext, json
from frappe import _, scrub, ValidationError from frappe import _, scrub, ValidationError
from frappe.utils import flt, comma_or, nowdate, getdate from frappe.utils import flt, comma_or, nowdate, getdate
from erpnext.accounts.utils import get_outstanding_invoices, get_account_currency, get_balance_on, get_allow_cost_center_in_entry_of_bs_account from erpnext.accounts.utils import get_outstanding_invoices, get_account_currency, get_balance_on
from erpnext.accounts.party import get_party_account from erpnext.accounts.party import get_party_account
from erpnext.accounts.doctype.journal_entry.journal_entry import get_default_bank_cash_account from erpnext.accounts.doctype.journal_entry.journal_entry import get_default_bank_cash_account
from erpnext.setup.utils import get_exchange_rate from erpnext.setup.utils import get_exchange_rate
@ -658,7 +658,7 @@ def get_outstanding_reference_documents(args):
.format(frappe.db.escape(args["voucher_type"]), frappe.db.escape(args["voucher_no"])) .format(frappe.db.escape(args["voucher_type"]), frappe.db.escape(args["voucher_no"]))
# Add cost center condition # Add cost center condition
if args.get("cost_center") and get_allow_cost_center_in_entry_of_bs_account(): if args.get("cost_center"):
condition += " and cost_center='%s'" % args.get("cost_center") condition += " and cost_center='%s'" % args.get("cost_center")
date_fields_dict = { date_fields_dict = {
@ -1029,14 +1029,14 @@ def get_payment_entry(dt, dn, party_amount=None, bank_account=None, bank_amount=
if bank_amount: if bank_amount:
received_amount = bank_amount received_amount = bank_amount
else: else:
received_amount = paid_amount * doc.conversion_rate received_amount = paid_amount * doc.get('conversion_rate', 1)
else: else:
received_amount = abs(outstanding_amount) received_amount = abs(outstanding_amount)
if bank_amount: if bank_amount:
paid_amount = bank_amount paid_amount = bank_amount
else: else:
# if party account currency and bank currency is different then populate paid amount as well # if party account currency and bank currency is different then populate paid amount as well
paid_amount = received_amount * doc.conversion_rate paid_amount = received_amount * doc.get('conversion_rate', 1)
pe = frappe.new_doc("Payment Entry") pe = frappe.new_doc("Payment Entry")
pe.payment_type = payment_type pe.payment_type = payment_type

View File

@ -460,11 +460,8 @@ class TestPaymentEntry(unittest.TestCase):
outstanding_amount = flt(frappe.db.get_value("Sales Invoice", si.name, "outstanding_amount")) outstanding_amount = flt(frappe.db.get_value("Sales Invoice", si.name, "outstanding_amount"))
self.assertEqual(outstanding_amount, 0) self.assertEqual(outstanding_amount, 0)
def test_payment_entry_against_sales_invoice_for_enable_allow_cost_center_in_entry_of_bs_account(self): def test_payment_entry_against_sales_invoice_with_cost_centre(self):
from erpnext.accounts.doctype.cost_center.test_cost_center import create_cost_center from erpnext.accounts.doctype.cost_center.test_cost_center import create_cost_center
accounts_settings = frappe.get_doc('Accounts Settings', 'Accounts Settings')
accounts_settings.allow_cost_center_in_entry_of_bs_account = 1
accounts_settings.save()
cost_center = "_Test Cost Center for BS Account - _TC" cost_center = "_Test Cost Center for BS Account - _TC"
create_cost_center(cost_center_name="_Test Cost Center for BS Account", company="_Test Company") create_cost_center(cost_center_name="_Test Cost Center for BS Account", company="_Test Company")
@ -499,39 +496,8 @@ class TestPaymentEntry(unittest.TestCase):
for gle in gl_entries: for gle in gl_entries:
self.assertEqual(expected_values[gle.account]["cost_center"], gle.cost_center) self.assertEqual(expected_values[gle.account]["cost_center"], gle.cost_center)
accounts_settings.allow_cost_center_in_entry_of_bs_account = 0 def test_payment_entry_against_purchase_invoice_with_cost_center(self):
accounts_settings.save()
def test_payment_entry_against_sales_invoice_for_disable_allow_cost_center_in_entry_of_bs_account(self):
accounts_settings = frappe.get_doc('Accounts Settings', 'Accounts Settings')
accounts_settings.allow_cost_center_in_entry_of_bs_account = 0
accounts_settings.save()
si = create_sales_invoice(debit_to="Debtors - _TC")
pe = get_payment_entry("Sales Invoice", si.name, bank_account="_Test Bank - _TC")
pe.reference_no = "112211-2"
pe.reference_date = nowdate()
pe.paid_to = "_Test Bank - _TC"
pe.paid_amount = si.grand_total
pe.insert()
pe.submit()
gl_entries = frappe.db.sql("""select account, cost_center, account_currency, debit, credit,
debit_in_account_currency, credit_in_account_currency
from `tabGL Entry` where voucher_type='Payment Entry' and voucher_no=%s
order by account asc""", pe.name, as_dict=1)
self.assertTrue(gl_entries)
for gle in gl_entries:
self.assertEqual(gle.cost_center, None)
def test_payment_entry_against_purchase_invoice_for_enable_allow_cost_center_in_entry_of_bs_account(self):
from erpnext.accounts.doctype.cost_center.test_cost_center import create_cost_center from erpnext.accounts.doctype.cost_center.test_cost_center import create_cost_center
accounts_settings = frappe.get_doc('Accounts Settings', 'Accounts Settings')
accounts_settings.allow_cost_center_in_entry_of_bs_account = 1
accounts_settings.save()
cost_center = "_Test Cost Center for BS Account - _TC" cost_center = "_Test Cost Center for BS Account - _TC"
create_cost_center(cost_center_name="_Test Cost Center for BS Account", company="_Test Company") create_cost_center(cost_center_name="_Test Cost Center for BS Account", company="_Test Company")
@ -566,40 +532,9 @@ class TestPaymentEntry(unittest.TestCase):
for gle in gl_entries: for gle in gl_entries:
self.assertEqual(expected_values[gle.account]["cost_center"], gle.cost_center) self.assertEqual(expected_values[gle.account]["cost_center"], gle.cost_center)
accounts_settings.allow_cost_center_in_entry_of_bs_account = 0 def test_payment_entry_account_and_party_balance_with_cost_center(self):
accounts_settings.save()
def test_payment_entry_against_purchase_invoice_for_disable_allow_cost_center_in_entry_of_bs_account(self):
accounts_settings = frappe.get_doc('Accounts Settings', 'Accounts Settings')
accounts_settings.allow_cost_center_in_entry_of_bs_account = 0
accounts_settings.save()
pi = make_purchase_invoice(credit_to="Creditors - _TC")
pe = get_payment_entry("Purchase Invoice", pi.name, bank_account="_Test Bank - _TC")
pe.reference_no = "112222-2"
pe.reference_date = nowdate()
pe.paid_from = "_Test Bank - _TC"
pe.paid_amount = pi.grand_total
pe.insert()
pe.submit()
gl_entries = frappe.db.sql("""select account, cost_center, account_currency, debit, credit,
debit_in_account_currency, credit_in_account_currency
from `tabGL Entry` where voucher_type='Payment Entry' and voucher_no=%s
order by account asc""", pe.name, as_dict=1)
self.assertTrue(gl_entries)
for gle in gl_entries:
self.assertEqual(gle.cost_center, None)
def test_payment_entry_account_and_party_balance_for_enable_allow_cost_center_in_entry_of_bs_account(self):
from erpnext.accounts.doctype.cost_center.test_cost_center import create_cost_center from erpnext.accounts.doctype.cost_center.test_cost_center import create_cost_center
from erpnext.accounts.utils import get_balance_on from erpnext.accounts.utils import get_balance_on
accounts_settings = frappe.get_doc('Accounts Settings', 'Accounts Settings')
accounts_settings.allow_cost_center_in_entry_of_bs_account = 1
accounts_settings.save()
cost_center = "_Test Cost Center for BS Account - _TC" cost_center = "_Test Cost Center for BS Account - _TC"
create_cost_center(cost_center_name="_Test Cost Center for BS Account", company="_Test Company") create_cost_center(cost_center_name="_Test Cost Center for BS Account", company="_Test Company")
@ -630,9 +565,6 @@ class TestPaymentEntry(unittest.TestCase):
self.assertEqual(expected_party_balance, party_balance) self.assertEqual(expected_party_balance, party_balance)
self.assertEqual(expected_party_account_balance, party_account_balance) self.assertEqual(expected_party_account_balance, party_account_balance)
accounts_settings.allow_cost_center_in_entry_of_bs_account = 0
accounts_settings.save()
def create_payment_terms_template(): def create_payment_terms_template():
create_payment_term('Basic Amount Receivable') create_payment_term('Basic Amount Receivable')

View File

@ -281,7 +281,8 @@ def reconcile_dr_cr_note(dr_cr_notes, company):
'party_type': d.party_type, 'party_type': d.party_type,
d.dr_or_cr: abs(d.allocated_amount), d.dr_or_cr: abs(d.allocated_amount),
'reference_type': d.against_voucher_type, 'reference_type': d.against_voucher_type,
'reference_name': d.against_voucher 'reference_name': d.against_voucher,
'cost_center': erpnext.get_default_cost_center(company)
}, },
{ {
'account': d.account, 'account': d.account,
@ -290,7 +291,8 @@ def reconcile_dr_cr_note(dr_cr_notes, company):
reconcile_dr_or_cr: (abs(d.allocated_amount) reconcile_dr_or_cr: (abs(d.allocated_amount)
if abs(d.unadjusted_amount) > abs(d.allocated_amount) else abs(d.unadjusted_amount)), if abs(d.unadjusted_amount) > abs(d.allocated_amount) else abs(d.unadjusted_amount)),
'reference_type': d.voucher_type, 'reference_type': d.voucher_type,
'reference_name': d.voucher_no 'reference_name': d.voucher_no,
'cost_center': erpnext.get_default_cost_center(company)
} }
] ]
}) })

View File

@ -26,6 +26,7 @@
"accounting_dimensions_section", "accounting_dimensions_section",
"cost_center", "cost_center",
"dimension_col_break", "dimension_col_break",
"project",
"supplier_invoice_details", "supplier_invoice_details",
"bill_no", "bill_no",
"column_break_15", "column_break_15",
@ -1598,6 +1599,12 @@
"show_days": 1, "show_days": 1,
"show_seconds": 1 "show_seconds": 1
}, },
{
"fieldname": "project",
"fieldtype": "Link",
"label": "Project",
"options": "Project"
},
{ {
"fieldname": "tax_withholding_category", "fieldname": "tax_withholding_category",
"fieldtype": "Link", "fieldtype": "Link",

View File

@ -438,6 +438,8 @@ class PurchaseInvoice(BuyingController):
self.make_tax_gl_entries(gl_entries) self.make_tax_gl_entries(gl_entries)
gl_entries = make_regional_gl_entries(gl_entries, self)
gl_entries = merge_similar_entries(gl_entries) gl_entries = merge_similar_entries(gl_entries)
self.make_payment_gl_entries(gl_entries) self.make_payment_gl_entries(gl_entries)
@ -476,6 +478,7 @@ class PurchaseInvoice(BuyingController):
if self.party_account_currency==self.company_currency else grand_total, if self.party_account_currency==self.company_currency else grand_total,
"against_voucher": self.return_against if cint(self.is_return) and self.return_against else self.name, "against_voucher": self.return_against if cint(self.is_return) and self.return_against else self.name,
"against_voucher_type": self.doctype, "against_voucher_type": self.doctype,
"project": self.project,
"cost_center": self.cost_center "cost_center": self.cost_center
}, self.party_account_currency, item=self) }, self.party_account_currency, item=self)
) )
@ -516,6 +519,7 @@ class PurchaseInvoice(BuyingController):
"account": warehouse_account[item.warehouse]['account'], "account": warehouse_account[item.warehouse]['account'],
"against": warehouse_account[item.from_warehouse]["account"], "against": warehouse_account[item.from_warehouse]["account"],
"cost_center": item.cost_center, "cost_center": item.cost_center,
"project": item.project or self.project,
"remarks": self.get("remarks") or _("Accounting Entry for Stock"), "remarks": self.get("remarks") or _("Accounting Entry for Stock"),
"debit": warehouse_debit_amount, "debit": warehouse_debit_amount,
}, warehouse_account[item.warehouse]["account_currency"], item=item)) }, warehouse_account[item.warehouse]["account_currency"], item=item))
@ -525,6 +529,7 @@ class PurchaseInvoice(BuyingController):
"account": warehouse_account[item.from_warehouse]['account'], "account": warehouse_account[item.from_warehouse]['account'],
"against": warehouse_account[item.warehouse]["account"], "against": warehouse_account[item.warehouse]["account"],
"cost_center": item.cost_center, "cost_center": item.cost_center,
"project": item.project or self.project,
"remarks": self.get("remarks") or _("Accounting Entry for Stock"), "remarks": self.get("remarks") or _("Accounting Entry for Stock"),
"debit": -1 * flt(item.base_net_amount, item.precision("base_net_amount")), "debit": -1 * flt(item.base_net_amount, item.precision("base_net_amount")),
}, warehouse_account[item.from_warehouse]["account_currency"], item=item)) }, warehouse_account[item.from_warehouse]["account_currency"], item=item))
@ -548,7 +553,7 @@ class PurchaseInvoice(BuyingController):
"debit": warehouse_debit_amount, "debit": warehouse_debit_amount,
"remarks": self.get("remarks") or _("Accounting Entry for Stock"), "remarks": self.get("remarks") or _("Accounting Entry for Stock"),
"cost_center": item.cost_center, "cost_center": item.cost_center,
"project": item.project "project": item.project or self.project
}, account_currency, item=item) }, account_currency, item=item)
) )
@ -561,7 +566,7 @@ class PurchaseInvoice(BuyingController):
"cost_center": item.cost_center, "cost_center": item.cost_center,
"remarks": self.get("remarks") or _("Accounting Entry for Stock"), "remarks": self.get("remarks") or _("Accounting Entry for Stock"),
"credit": flt(amount), "credit": flt(amount),
"project": item.project "project": item.project or self.project
}, item=item)) }, item=item))
# sub-contracting warehouse # sub-contracting warehouse
@ -574,6 +579,7 @@ class PurchaseInvoice(BuyingController):
"account": supplier_warehouse_account, "account": supplier_warehouse_account,
"against": item.expense_account, "against": item.expense_account,
"cost_center": item.cost_center, "cost_center": item.cost_center,
"project": item.project or self.project,
"remarks": self.get("remarks") or _("Accounting Entry for Stock"), "remarks": self.get("remarks") or _("Accounting Entry for Stock"),
"credit": flt(item.rm_supp_cost) "credit": flt(item.rm_supp_cost)
}, warehouse_account[self.supplier_warehouse]["account_currency"], item=item)) }, warehouse_account[self.supplier_warehouse]["account_currency"], item=item))
@ -606,7 +612,7 @@ class PurchaseInvoice(BuyingController):
"against": self.supplier, "against": self.supplier,
"debit": amount, "debit": amount,
"cost_center": item.cost_center, "cost_center": item.cost_center,
"project": item.project "project": item.project or self.project
}, account_currency, item=item)) }, account_currency, item=item))
# If asset is bought through this document and not linked to PR # If asset is bought through this document and not linked to PR
@ -619,7 +625,7 @@ class PurchaseInvoice(BuyingController):
"cost_center": item.cost_center, "cost_center": item.cost_center,
"remarks": self.get("remarks") or _("Accounting Entry for Stock"), "remarks": self.get("remarks") or _("Accounting Entry for Stock"),
"credit": flt(item.landed_cost_voucher_amount), "credit": flt(item.landed_cost_voucher_amount),
"project": item.project "project": item.project or self.project
}, item=item)) }, item=item))
gl_entries.append(self.get_gl_dict({ gl_entries.append(self.get_gl_dict({
@ -628,7 +634,7 @@ class PurchaseInvoice(BuyingController):
"cost_center": item.cost_center, "cost_center": item.cost_center,
"remarks": self.get("remarks") or _("Accounting Entry for Stock"), "remarks": self.get("remarks") or _("Accounting Entry for Stock"),
"debit": flt(item.landed_cost_voucher_amount), "debit": flt(item.landed_cost_voucher_amount),
"project": item.project "project": item.project or self.project
}, item=item)) }, item=item))
# update gross amount of asset bought through this document # update gross amount of asset bought through this document
@ -654,7 +660,8 @@ class PurchaseInvoice(BuyingController):
"against": self.supplier, "against": self.supplier,
"debit": flt(item.item_tax_amount, item.precision("item_tax_amount")), "debit": flt(item.item_tax_amount, item.precision("item_tax_amount")),
"remarks": self.remarks or "Accounting Entry for Stock", "remarks": self.remarks or "Accounting Entry for Stock",
"cost_center": self.cost_center "cost_center": self.cost_center,
"project": item.project or self.project
}, item=item) }, item=item)
) )
@ -683,7 +690,8 @@ class PurchaseInvoice(BuyingController):
"debit": base_asset_amount, "debit": base_asset_amount,
"debit_in_account_currency": (base_asset_amount "debit_in_account_currency": (base_asset_amount
if arbnb_currency == self.company_currency else asset_amount), if arbnb_currency == self.company_currency else asset_amount),
"cost_center": item.cost_center "cost_center": item.cost_center,
"project": item.project or self.project
}, item=item)) }, item=item))
if item.item_tax_amount: if item.item_tax_amount:
@ -693,6 +701,7 @@ class PurchaseInvoice(BuyingController):
"against": self.supplier, "against": self.supplier,
"remarks": self.get("remarks") or _("Accounting Entry for Asset"), "remarks": self.get("remarks") or _("Accounting Entry for Asset"),
"cost_center": item.cost_center, "cost_center": item.cost_center,
"project": item.project or self.project,
"credit": item.item_tax_amount, "credit": item.item_tax_amount,
"credit_in_account_currency": (item.item_tax_amount "credit_in_account_currency": (item.item_tax_amount
if asset_eiiav_currency == self.company_currency else if asset_eiiav_currency == self.company_currency else
@ -709,7 +718,8 @@ class PurchaseInvoice(BuyingController):
"debit": base_asset_amount, "debit": base_asset_amount,
"debit_in_account_currency": (base_asset_amount "debit_in_account_currency": (base_asset_amount
if cwip_account_currency == self.company_currency else asset_amount), if cwip_account_currency == self.company_currency else asset_amount),
"cost_center": self.cost_center "cost_center": self.cost_center,
"project": item.project or self.project
}, item=item)) }, item=item))
if item.item_tax_amount and not cint(erpnext.is_perpetual_inventory_enabled(self.company)): if item.item_tax_amount and not cint(erpnext.is_perpetual_inventory_enabled(self.company)):
@ -720,6 +730,7 @@ class PurchaseInvoice(BuyingController):
"remarks": self.get("remarks") or _("Accounting Entry for Asset"), "remarks": self.get("remarks") or _("Accounting Entry for Asset"),
"cost_center": item.cost_center, "cost_center": item.cost_center,
"credit": item.item_tax_amount, "credit": item.item_tax_amount,
"project": item.project or self.project,
"credit_in_account_currency": (item.item_tax_amount "credit_in_account_currency": (item.item_tax_amount
if asset_eiiav_currency == self.company_currency else if asset_eiiav_currency == self.company_currency else
item.item_tax_amount / self.conversion_rate) item.item_tax_amount / self.conversion_rate)
@ -735,7 +746,7 @@ class PurchaseInvoice(BuyingController):
"cost_center": item.cost_center, "cost_center": item.cost_center,
"remarks": self.get("remarks") or _("Accounting Entry for Stock"), "remarks": self.get("remarks") or _("Accounting Entry for Stock"),
"credit": flt(item.landed_cost_voucher_amount), "credit": flt(item.landed_cost_voucher_amount),
"project": item.project "project": item.project or self.project
}, item=item)) }, item=item))
gl_entries.append(self.get_gl_dict({ gl_entries.append(self.get_gl_dict({
@ -744,7 +755,7 @@ class PurchaseInvoice(BuyingController):
"cost_center": item.cost_center, "cost_center": item.cost_center,
"remarks": self.get("remarks") or _("Accounting Entry for Stock"), "remarks": self.get("remarks") or _("Accounting Entry for Stock"),
"debit": flt(item.landed_cost_voucher_amount), "debit": flt(item.landed_cost_voucher_amount),
"project": item.project "project": item.project or self.project
}, item=item)) }, item=item))
# update gross amount of assets bought through this document # update gross amount of assets bought through this document
@ -779,7 +790,7 @@ class PurchaseInvoice(BuyingController):
"debit": stock_adjustment_amt, "debit": stock_adjustment_amt,
"remarks": self.get("remarks") or _("Stock Adjustment"), "remarks": self.get("remarks") or _("Stock Adjustment"),
"cost_center": item.cost_center, "cost_center": item.cost_center,
"project": item.project "project": item.project or self.project
}, account_currency, item=item) }, account_currency, item=item)
) )
@ -871,7 +882,8 @@ class PurchaseInvoice(BuyingController):
if self.party_account_currency==self.company_currency else self.paid_amount, if self.party_account_currency==self.company_currency else self.paid_amount,
"against_voucher": self.return_against if cint(self.is_return) and self.return_against else self.name, "against_voucher": self.return_against if cint(self.is_return) and self.return_against else self.name,
"against_voucher_type": self.doctype, "against_voucher_type": self.doctype,
"cost_center": self.cost_center "cost_center": self.cost_center,
"project": self.project
}, self.party_account_currency, item=self) }, self.party_account_currency, item=self)
) )
@ -903,7 +915,8 @@ class PurchaseInvoice(BuyingController):
if self.party_account_currency==self.company_currency else self.write_off_amount, if self.party_account_currency==self.company_currency else self.write_off_amount,
"against_voucher": self.return_against if cint(self.is_return) and self.return_against else self.name, "against_voucher": self.return_against if cint(self.is_return) and self.return_against else self.name,
"against_voucher_type": self.doctype, "against_voucher_type": self.doctype,
"cost_center": self.cost_center "cost_center": self.cost_center,
"project": self.project
}, self.party_account_currency, item=self) }, self.party_account_currency, item=self)
) )
gl_entries.append( gl_entries.append(
@ -1097,6 +1110,10 @@ def get_list_context(context=None):
}) })
return list_context return list_context
@erpnext.allow_regional
def make_regional_gl_entries(gl_entries, doc):
return gl_entries
@frappe.whitelist() @frappe.whitelist()
def make_debit_note(source_name, target_doc=None): def make_debit_note(source_name, target_doc=None):
from erpnext.controllers.sales_and_purchase_return import make_return_doc from erpnext.controllers.sales_and_purchase_return import make_return_doc

View File

@ -14,6 +14,7 @@ from erpnext.stock.doctype.purchase_receipt.test_purchase_receipt import set_per
from erpnext.controllers.accounts_controller import get_payment_terms from erpnext.controllers.accounts_controller import get_payment_terms
from erpnext.exceptions import InvalidCurrency from erpnext.exceptions import InvalidCurrency
from erpnext.stock.doctype.stock_entry.test_stock_entry import get_qty_after_transaction from erpnext.stock.doctype.stock_entry.test_stock_entry import get_qty_after_transaction
from erpnext.projects.doctype.project.test_project import make_project
from erpnext.accounts.doctype.account.test_account import get_inventory_account, create_account from erpnext.accounts.doctype.account.test_account import get_inventory_account, create_account
from erpnext.stock.doctype.item.test_item import create_item from erpnext.stock.doctype.item.test_item import create_item
@ -435,6 +436,8 @@ class TestPurchaseInvoice(unittest.TestCase):
) )
def test_total_purchase_cost_for_project(self): def test_total_purchase_cost_for_project(self):
make_project({'project_name':'_Test Project'})
existing_purchase_cost = frappe.db.sql("""select sum(base_net_amount) existing_purchase_cost = frappe.db.sql("""select sum(base_net_amount)
from `tabPurchase Invoice Item` where project = '_Test Project' and docstatus=1""") from `tabPurchase Invoice Item` where project = '_Test Project' and docstatus=1""")
existing_purchase_cost = existing_purchase_cost and existing_purchase_cost[0][0] or 0 existing_purchase_cost = existing_purchase_cost and existing_purchase_cost[0][0] or 0
@ -808,11 +811,8 @@ class TestPurchaseInvoice(unittest.TestCase):
pi_doc = frappe.get_doc('Purchase Invoice', pi.name) pi_doc = frappe.get_doc('Purchase Invoice', pi.name)
self.assertEqual(pi_doc.outstanding_amount, 0) self.assertEqual(pi_doc.outstanding_amount, 0)
def test_purchase_invoice_for_enable_allow_cost_center_in_entry_of_bs_account(self): def test_purchase_invoice_with_cost_center(self):
from erpnext.accounts.doctype.cost_center.test_cost_center import create_cost_center from erpnext.accounts.doctype.cost_center.test_cost_center import create_cost_center
accounts_settings = frappe.get_doc('Accounts Settings', 'Accounts Settings')
accounts_settings.allow_cost_center_in_entry_of_bs_account = 1
accounts_settings.save()
cost_center = "_Test Cost Center for BS Account - _TC" cost_center = "_Test Cost Center for BS Account - _TC"
create_cost_center(cost_center_name="_Test Cost Center for BS Account", company="_Test Company") create_cost_center(cost_center_name="_Test Cost Center for BS Account", company="_Test Company")
@ -838,13 +838,7 @@ class TestPurchaseInvoice(unittest.TestCase):
for gle in gl_entries: for gle in gl_entries:
self.assertEqual(expected_values[gle.account]["cost_center"], gle.cost_center) self.assertEqual(expected_values[gle.account]["cost_center"], gle.cost_center)
accounts_settings.allow_cost_center_in_entry_of_bs_account = 0 def test_purchase_invoice_without_cost_center(self):
accounts_settings.save()
def test_purchase_invoice_for_disable_allow_cost_center_in_entry_of_bs_account(self):
accounts_settings = frappe.get_doc('Accounts Settings', 'Accounts Settings')
accounts_settings.allow_cost_center_in_entry_of_bs_account = 0
accounts_settings.save()
cost_center = "_Test Cost Center - _TC" cost_center = "_Test Cost Center - _TC"
pi = make_purchase_invoice(credit_to="Creditors - _TC") pi = make_purchase_invoice(credit_to="Creditors - _TC")
@ -867,6 +861,43 @@ class TestPurchaseInvoice(unittest.TestCase):
for gle in gl_entries: for gle in gl_entries:
self.assertEqual(expected_values[gle.account]["cost_center"], gle.cost_center) self.assertEqual(expected_values[gle.account]["cost_center"], gle.cost_center)
def test_purchase_invoice_with_project_link(self):
project = make_project({
'project_name': 'Purchase Invoice Project',
'project_template_name': 'Test Project Template',
'start_date': '2020-01-01'
})
item_project = make_project({
'project_name': 'Purchase Invoice Item Project',
'project_template_name': 'Test Project Template',
'start_date': '2019-06-01'
})
pi = make_purchase_invoice(credit_to="Creditors - _TC" ,do_not_save=1)
pi.items[0].project = item_project.project_name
pi.project = project.project_name
pi.submit()
expected_values = {
"Creditors - _TC": {
"project": project.project_name
},
"_Test Account Cost for Goods Sold - _TC": {
"project": item_project.project_name
}
}
gl_entries = frappe.db.sql("""select account, cost_center, project, account_currency, debit, credit,
debit_in_account_currency, credit_in_account_currency
from `tabGL Entry` where voucher_type='Purchase Invoice' and voucher_no=%s
order by account asc""", pi.name, as_dict=1)
self.assertTrue(gl_entries)
for gle in gl_entries:
self.assertEqual(expected_values[gle.account]["project"], gle.project)
def test_deferred_expense_via_journal_entry(self): def test_deferred_expense_via_journal_entry(self):
deferred_account = create_account(account_name="Deferred Expense", deferred_account = create_account(account_name="Deferred Expense",
parent_account="Current Assets - _TC", company="_Test Company") parent_account="Current Assets - _TC", company="_Test Company")

View File

@ -790,7 +790,8 @@ class SalesInvoice(SellingController):
if self.party_account_currency==self.company_currency else grand_total, if self.party_account_currency==self.company_currency else grand_total,
"against_voucher": self.return_against if cint(self.is_return) and self.return_against else self.name, "against_voucher": self.return_against if cint(self.is_return) and self.return_against else self.name,
"against_voucher_type": self.doctype, "against_voucher_type": self.doctype,
"cost_center": self.cost_center "cost_center": self.cost_center,
"project": self.project
}, self.party_account_currency, item=self) }, self.party_account_currency, item=self)
) )
@ -845,7 +846,8 @@ class SalesInvoice(SellingController):
"credit_in_account_currency": (flt(item.base_net_amount, item.precision("base_net_amount")) "credit_in_account_currency": (flt(item.base_net_amount, item.precision("base_net_amount"))
if account_currency==self.company_currency if account_currency==self.company_currency
else flt(item.net_amount, item.precision("net_amount"))), else flt(item.net_amount, item.precision("net_amount"))),
"cost_center": item.cost_center "cost_center": item.cost_center,
"project": item.project or self.project
}, account_currency, item=item) }, account_currency, item=item)
) )
@ -926,7 +928,8 @@ class SalesInvoice(SellingController):
if self.party_account_currency==self.company_currency else flt(self.change_amount), if self.party_account_currency==self.company_currency else flt(self.change_amount),
"against_voucher": self.return_against if cint(self.is_return) and self.return_against else self.name, "against_voucher": self.return_against if cint(self.is_return) and self.return_against else self.name,
"against_voucher_type": self.doctype, "against_voucher_type": self.doctype,
"cost_center": self.cost_center "cost_center": self.cost_center,
"project": self.project
}, self.party_account_currency, item=self) }, self.party_account_currency, item=self)
) )
@ -959,7 +962,8 @@ class SalesInvoice(SellingController):
else flt(self.write_off_amount, self.precision("write_off_amount"))), else flt(self.write_off_amount, self.precision("write_off_amount"))),
"against_voucher": self.return_against if cint(self.is_return) else self.name, "against_voucher": self.return_against if cint(self.is_return) else self.name,
"against_voucher_type": self.doctype, "against_voucher_type": self.doctype,
"cost_center": self.cost_center "cost_center": self.cost_center,
"project": self.project
}, self.party_account_currency, item=self) }, self.party_account_currency, item=self)
) )
gl_entries.append( gl_entries.append(
@ -1109,7 +1113,10 @@ class SalesInvoice(SellingController):
expiry_date=self.posting_date, include_expired_entry=True) expiry_date=self.posting_date, include_expired_entry=True)
if lp_details and getdate(lp_details.from_date) <= getdate(self.posting_date) and \ if lp_details and getdate(lp_details.from_date) <= getdate(self.posting_date) and \
(not lp_details.to_date or getdate(lp_details.to_date) >= getdate(self.posting_date)): (not lp_details.to_date or getdate(lp_details.to_date) >= getdate(self.posting_date)):
points_earned = cint(eligible_amount/lp_details.collection_factor)
collection_factor = lp_details.collection_factor if lp_details.collection_factor else 1.0
points_earned = cint(eligible_amount/collection_factor)
doc = frappe.get_doc({ doc = frappe.get_doc({
"doctype": "Loyalty Point Entry", "doctype": "Loyalty Point Entry",
"company": self.company, "company": self.company,

View File

@ -3,6 +3,7 @@
"company": "_Test Company", "company": "_Test Company",
"conversion_rate": 1.0, "conversion_rate": 1.0,
"currency": "INR", "currency": "INR",
"cost_center": "_Test Cost Center - _TC",
"customer": "_Test Customer", "customer": "_Test Customer",
"customer_name": "_Test Customer", "customer_name": "_Test Customer",
"debit_to": "_Test Receivable - _TC", "debit_to": "_Test Receivable - _TC",
@ -38,6 +39,7 @@
"description": "VAT", "description": "VAT",
"doctype": "Sales Taxes and Charges", "doctype": "Sales Taxes and Charges",
"parentfield": "taxes", "parentfield": "taxes",
"cost_center": "_Test Cost Center - _TC",
"rate": 6 "rate": 6
}, },
{ {
@ -46,6 +48,7 @@
"description": "Service Tax", "description": "Service Tax",
"doctype": "Sales Taxes and Charges", "doctype": "Sales Taxes and Charges",
"parentfield": "taxes", "parentfield": "taxes",
"cost_center": "_Test Cost Center - _TC",
"rate": 6.36 "rate": 6.36
} }
], ],
@ -76,6 +79,7 @@
"customer_name": "_Test Customer", "customer_name": "_Test Customer",
"debit_to": "_Test Receivable - _TC", "debit_to": "_Test Receivable - _TC",
"doctype": "Sales Invoice", "doctype": "Sales Invoice",
"cost_center": "_Test Cost Center - _TC",
"items": [ "items": [
{ {
"amount": 500.0, "amount": 500.0,
@ -108,6 +112,7 @@
"description": "VAT", "description": "VAT",
"doctype": "Sales Taxes and Charges", "doctype": "Sales Taxes and Charges",
"parentfield": "taxes", "parentfield": "taxes",
"cost_center": "_Test Cost Center - _TC",
"rate": 16 "rate": 16
}, },
{ {
@ -116,6 +121,7 @@
"description": "Service Tax", "description": "Service Tax",
"doctype": "Sales Taxes and Charges", "doctype": "Sales Taxes and Charges",
"parentfield": "taxes", "parentfield": "taxes",
"cost_center": "_Test Cost Center - _TC",
"rate": 10 "rate": 10
} }
], ],
@ -132,6 +138,7 @@
"customer_name": "_Test Customer", "customer_name": "_Test Customer",
"debit_to": "_Test Receivable - _TC", "debit_to": "_Test Receivable - _TC",
"doctype": "Sales Invoice", "doctype": "Sales Invoice",
"cost_center": "_Test Cost Center - _TC",
"items": [ "items": [
{ {
"cost_center": "_Test Cost Center - _TC", "cost_center": "_Test Cost Center - _TC",
@ -259,6 +266,7 @@
"customer_name": "_Test Customer", "customer_name": "_Test Customer",
"debit_to": "_Test Receivable - _TC", "debit_to": "_Test Receivable - _TC",
"doctype": "Sales Invoice", "doctype": "Sales Invoice",
"cost_center": "_Test Cost Center - _TC",
"items": [ "items": [
{ {
"cost_center": "_Test Cost Center - _TC", "cost_center": "_Test Cost Center - _TC",

View File

@ -1640,11 +1640,8 @@ class TestSalesInvoice(unittest.TestCase):
si_doc = frappe.get_doc('Sales Invoice', si.name) si_doc = frappe.get_doc('Sales Invoice', si.name)
self.assertEqual(si_doc.outstanding_amount, 0) self.assertEqual(si_doc.outstanding_amount, 0)
def test_sales_invoice_for_enable_allow_cost_center_in_entry_of_bs_account(self): def test_sales_invoice_with_cost_center(self):
from erpnext.accounts.doctype.cost_center.test_cost_center import create_cost_center from erpnext.accounts.doctype.cost_center.test_cost_center import create_cost_center
accounts_settings = frappe.get_doc('Accounts Settings', 'Accounts Settings')
accounts_settings.allow_cost_center_in_entry_of_bs_account = 1
accounts_settings.save()
cost_center = "_Test Cost Center for BS Account - _TC" cost_center = "_Test Cost Center for BS Account - _TC"
create_cost_center(cost_center_name="_Test Cost Center for BS Account", company="_Test Company") create_cost_center(cost_center_name="_Test Cost Center for BS Account", company="_Test Company")
@ -1670,13 +1667,46 @@ class TestSalesInvoice(unittest.TestCase):
for gle in gl_entries: for gle in gl_entries:
self.assertEqual(expected_values[gle.account]["cost_center"], gle.cost_center) self.assertEqual(expected_values[gle.account]["cost_center"], gle.cost_center)
accounts_settings.allow_cost_center_in_entry_of_bs_account = 0 def test_sales_invoice_with_project_link(self):
accounts_settings.save() from erpnext.projects.doctype.project.test_project import make_project
def test_sales_invoice_for_disable_allow_cost_center_in_entry_of_bs_account(self): project = make_project({
accounts_settings = frappe.get_doc('Accounts Settings', 'Accounts Settings') 'project_name': 'Sales Invoice Project',
accounts_settings.allow_cost_center_in_entry_of_bs_account = 1 'project_template_name': 'Test Project Template',
accounts_settings.save() 'start_date': '2020-01-01'
})
item_project = make_project({
'project_name': 'Sales Invoice Item Project',
'project_template_name': 'Test Project Template',
'start_date': '2019-06-01'
})
sales_invoice = create_sales_invoice(do_not_save=1)
sales_invoice.items[0].project = item_project.project_name
sales_invoice.project = project.project_name
sales_invoice.submit()
expected_values = {
"Debtors - _TC": {
"project": project.project_name
},
"Sales - _TC": {
"project": item_project.project_name
}
}
gl_entries = frappe.db.sql("""select account, cost_center, project, account_currency, debit, credit,
debit_in_account_currency, credit_in_account_currency
from `tabGL Entry` where voucher_type='Sales Invoice' and voucher_no=%s
order by account asc""", sales_invoice.name, as_dict=1)
self.assertTrue(gl_entries)
for gle in gl_entries:
self.assertEqual(expected_values[gle.account]["project"], gle.project)
def test_sales_invoice_without_cost_center(self):
cost_center = "_Test Cost Center - _TC" cost_center = "_Test Cost Center - _TC"
si = create_sales_invoice(debit_to="Debtors - _TC") si = create_sales_invoice(debit_to="Debtors - _TC")
@ -1699,9 +1729,6 @@ class TestSalesInvoice(unittest.TestCase):
for gle in gl_entries: for gle in gl_entries:
self.assertEqual(expected_values[gle.account]["cost_center"], gle.cost_center) self.assertEqual(expected_values[gle.account]["cost_center"], gle.cost_center)
accounts_settings.allow_cost_center_in_entry_of_bs_account = 0
accounts_settings.save()
def test_deferred_revenue(self): def test_deferred_revenue(self):
deferred_account = create_account(account_name="Deferred Revenue", deferred_account = create_account(account_name="Deferred Revenue",
parent_account="Current Liabilities - _TC", company="_Test Company") parent_account="Current Liabilities - _TC", company="_Test Company")

View File

@ -94,6 +94,7 @@
"accounting_dimensions_section", "accounting_dimensions_section",
"cost_center", "cost_center",
"dimension_col_break", "dimension_col_break",
"project",
"section_break_54", "section_break_54",
"page_break" "page_break"
], ],
@ -783,12 +784,18 @@
"fieldtype": "Link", "fieldtype": "Link",
"label": "Finance Book", "label": "Finance Book",
"options": "Finance Book" "options": "Finance Book"
},
{
"fieldname": "project",
"fieldtype": "Link",
"label": "Project",
"options": "Project"
} }
], ],
"idx": 1, "idx": 1,
"istable": 1, "istable": 1,
"links": [], "links": [],
"modified": "2019-12-04 12:22:38.517710", "modified": "2020-03-11 12:24:41.749986",
"modified_by": "Administrator", "modified_by": "Administrator",
"module": "Accounts", "module": "Accounts",
"name": "Sales Invoice Item", "name": "Sales Invoice Item",

View File

@ -334,10 +334,9 @@ def compute_data(filters, company_currency, profit_data, period_list, light_mapp
def execute(filters=None): def execute(filters=None):
if not filters.periodicity: filters.periodicity = "Monthly" if not filters.periodicity: filters.periodicity = "Monthly"
period_list = get_period_list( period_list = get_period_list(filters.from_fiscal_year, filters.to_fiscal_year,
filters.from_fiscal_year, filters.to_fiscal_year, filters.periodicity, filters.period_start_date, filters.period_end_date, filters.filter_based_on,
filters.accumulated_values, filters.company filters.periodicity, company=filters.company)
)
mappers = get_mappers_from_db() mappers = get_mappers_from_db()

View File

@ -44,7 +44,7 @@
</tr> </tr>
</thead> </thead>
<tbody> <tbody>
{% for(let j=0, k=data.length-1; j<k; j++) { %} {% for(let j=0, k=data.length; j<k; j++) { %}
{% {%
var row = data[j]; var row = data[j];
var row_class = data[j].parent_account ? "" : "financial-statements-important"; var row_class = data[j].parent_account ? "" : "financial-statements-important";

View File

@ -8,6 +8,7 @@ from __future__ import unicode_literals
import re import re
from past.builtins import cmp from past.builtins import cmp
import functools import functools
import math
import frappe, erpnext import frappe, erpnext
from erpnext.accounts.report.utils import get_currency, convert_to_presentation_currency from erpnext.accounts.report.utils import get_currency, convert_to_presentation_currency
@ -45,10 +46,7 @@ def get_period_list(from_fiscal_year, to_fiscal_year, period_start_date, period_
start_date = year_start_date start_date = year_start_date
months = get_months(year_start_date, year_end_date) months = get_months(year_start_date, year_end_date)
if (months // months_to_add) != (months / months_to_add): for i in range(math.ceil(months / months_to_add)):
months += months_to_add
for i in range(months // months_to_add):
period = frappe._dict({ period = frappe._dict({
"from_date": start_date "from_date": start_date
}) })

View File

@ -144,14 +144,12 @@ def get_balance_on(account=None, date=None, party_type=None, party=None, company
# hence, assuming balance as 0.0 # hence, assuming balance as 0.0
return 0.0 return 0.0
allow_cost_center_in_entry_of_bs_account = get_allow_cost_center_in_entry_of_bs_account()
if account: if account:
report_type = acc.report_type report_type = acc.report_type
else: else:
report_type = "" report_type = ""
if cost_center and (allow_cost_center_in_entry_of_bs_account or report_type =='Profit and Loss'): if cost_center and report_type == 'Profit and Loss':
cc = frappe.get_doc("Cost Center", cost_center) cc = frappe.get_doc("Cost Center", cost_center)
if cc.is_group: if cc.is_group:
cond.append(""" exists ( cond.append(""" exists (
@ -897,11 +895,6 @@ def get_coa(doctype, parent, is_root, chart=None):
return accounts return accounts
def get_allow_cost_center_in_entry_of_bs_account():
def generator():
return cint(frappe.db.get_value('Accounts Settings', None, 'allow_cost_center_in_entry_of_bs_account'))
return frappe.local_cache("get_allow_cost_center_in_entry_of_bs_account", (), generator, regenerate_if_none=True)
def get_stock_accounts(company): def get_stock_accounts(company):
return frappe.get_all("Account", filters = { return frappe.get_all("Account", filters = {
"account_type": "Stock", "account_type": "Stock",

View File

@ -10,7 +10,7 @@ from erpnext.accounts.doctype.accounting_dimension.accounting_dimension import g
def post_depreciation_entries(date=None): def post_depreciation_entries(date=None):
# Return if automatic booking of asset depreciation is disabled # Return if automatic booking of asset depreciation is disabled
if not cint(frappe.db.get_single_value("Accounts Settings", "book_asset_depreciation_entry_automatically")): if not cint(frappe.db.get_value("Accounts Settings", None, "book_asset_depreciation_entry_automatically")):
return return
if not date: if not date:
@ -58,7 +58,8 @@ def make_depreciation_entry(asset_name, date=None):
"account": accumulated_depreciation_account, "account": accumulated_depreciation_account,
"credit_in_account_currency": d.depreciation_amount, "credit_in_account_currency": d.depreciation_amount,
"reference_type": "Asset", "reference_type": "Asset",
"reference_name": asset.name "reference_name": asset.name,
"cost_center": ""
} }
debit_entry = { debit_entry = {
@ -196,12 +197,14 @@ def get_gl_entries_on_asset_disposal(asset, selling_amount=0, finance_book=None)
{ {
"account": fixed_asset_account, "account": fixed_asset_account,
"credit_in_account_currency": asset.gross_purchase_amount, "credit_in_account_currency": asset.gross_purchase_amount,
"credit": asset.gross_purchase_amount "credit": asset.gross_purchase_amount,
"cost_center": depreciation_cost_center
}, },
{ {
"account": accumulated_depr_account, "account": accumulated_depr_account,
"debit_in_account_currency": accumulated_depr_amount, "debit_in_account_currency": accumulated_depr_amount,
"debit": accumulated_depr_amount "debit": accumulated_depr_amount,
"cost_center": depreciation_cost_center
} }
] ]

View File

@ -67,4 +67,5 @@ class TestProcurementTracker(unittest.TestCase):
"expected_delivery_date": date_obj, "expected_delivery_date": date_obj,
"actual_delivery_date": date_obj "actual_delivery_date": date_obj
} }
return expected_data return expected_data

View File

@ -96,6 +96,7 @@ class StockController(AccountsController):
"account": warehouse_account[sle.warehouse]["account"], "account": warehouse_account[sle.warehouse]["account"],
"against": item_row.expense_account, "against": item_row.expense_account,
"cost_center": item_row.cost_center, "cost_center": item_row.cost_center,
"project": item_row.project or self.get('project'),
"remarks": self.get("remarks") or "Accounting Entry for Stock", "remarks": self.get("remarks") or "Accounting Entry for Stock",
"debit": flt(sle.stock_value_difference, precision), "debit": flt(sle.stock_value_difference, precision),
"is_opening": item_row.get("is_opening") or self.get("is_opening") or "No", "is_opening": item_row.get("is_opening") or self.get("is_opening") or "No",
@ -106,6 +107,7 @@ class StockController(AccountsController):
"account": item_row.expense_account, "account": item_row.expense_account,
"against": warehouse_account[sle.warehouse]["account"], "against": warehouse_account[sle.warehouse]["account"],
"cost_center": item_row.cost_center, "cost_center": item_row.cost_center,
"project": item_row.project or self.get('project'),
"remarks": self.get("remarks") or "Accounting Entry for Stock", "remarks": self.get("remarks") or "Accounting Entry for Stock",
"credit": flt(sle.stock_value_difference, precision), "credit": flt(sle.stock_value_difference, precision),
"project": item_row.get("project") or self.get("project"), "project": item_row.get("project") or self.get("project"),

View File

@ -17,7 +17,8 @@ def get_columns():
{ {
"fieldname": "lead_owner", "fieldname": "lead_owner",
"label": _("Lead Owner"), "label": _("Lead Owner"),
"fieldtype": "Data", "fieldtype": "Link",
"options": "User",
"width": "130" "width": "130"
}, },
{ {

View File

@ -246,7 +246,7 @@ doc_events = {
"on_trash": "erpnext.regional.check_deletion_permission" "on_trash": "erpnext.regional.check_deletion_permission"
}, },
"Purchase Invoice": { "Purchase Invoice": {
"on_submit": "erpnext.regional.india.utils.make_reverse_charge_entries" "validate": "erpnext.regional.india.utils.update_grand_total_for_rcm"
}, },
"Payment Entry": { "Payment Entry": {
"on_submit": ["erpnext.regional.create_transaction_log", "erpnext.accounts.doctype.payment_request.payment_request.update_payment_req_status"], "on_submit": ["erpnext.regional.create_transaction_log", "erpnext.accounts.doctype.payment_request.payment_request.update_payment_req_status"],
@ -374,7 +374,8 @@ regional_overrides = {
'erpnext.controllers.taxes_and_totals.get_itemised_tax_breakup_data': 'erpnext.regional.india.utils.get_itemised_tax_breakup_data', 'erpnext.controllers.taxes_and_totals.get_itemised_tax_breakup_data': 'erpnext.regional.india.utils.get_itemised_tax_breakup_data',
'erpnext.accounts.party.get_regional_address_details': 'erpnext.regional.india.utils.get_regional_address_details', 'erpnext.accounts.party.get_regional_address_details': 'erpnext.regional.india.utils.get_regional_address_details',
'erpnext.hr.utils.calculate_annual_eligible_hra_exemption': 'erpnext.regional.india.utils.calculate_annual_eligible_hra_exemption', 'erpnext.hr.utils.calculate_annual_eligible_hra_exemption': 'erpnext.regional.india.utils.calculate_annual_eligible_hra_exemption',
'erpnext.hr.utils.calculate_hra_exemption_for_period': 'erpnext.regional.india.utils.calculate_hra_exemption_for_period' 'erpnext.hr.utils.calculate_hra_exemption_for_period': 'erpnext.regional.india.utils.calculate_hra_exemption_for_period',
'erpnext.accounts.doctype.purchase_invoice.purchase_invoice.make_regional_gl_entries': 'erpnext.regional.india.utils.make_regional_gl_entries'
}, },
'United Arab Emirates': { 'United Arab Emirates': {
'erpnext.controllers.taxes_and_totals.update_itemised_tax_data': 'erpnext.regional.united_arab_emirates.utils.update_itemised_tax_data' 'erpnext.controllers.taxes_and_totals.update_itemised_tax_data': 'erpnext.regional.united_arab_emirates.utils.update_itemised_tax_data'

View File

@ -120,12 +120,14 @@ def make_bank_entry(dt, dn):
"reference_type": "Employee Advance", "reference_type": "Employee Advance",
"reference_name": doc.name, "reference_name": doc.name,
"party_type": "Employee", "party_type": "Employee",
"cost_center": erpnext.get_default_cost_center(doc.company),
"party": doc.employee, "party": doc.employee,
"is_advance": "Yes" "is_advance": "Yes"
}) })
je.append("accounts", { je.append("accounts", {
"account": payment_account.account, "account": payment_account.account,
"cost_center": erpnext.get_default_cost_center(doc.company),
"credit_in_account_currency": flt(doc.advance_amount), "credit_in_account_currency": flt(doc.advance_amount),
"account_currency": payment_account.account_currency, "account_currency": payment_account.account_currency,
"account_type": payment_account.account_type "account_type": payment_account.account_type

View File

@ -41,8 +41,7 @@
"fieldtype": "Select", "fieldtype": "Select",
"in_list_view": 1, "in_list_view": 1,
"label": "Log Type", "label": "Log Type",
"options": "\nIN\nOUT", "options": "\nIN\nOUT"
"reqd": 1
}, },
{ {
"fieldname": "shift", "fieldname": "shift",
@ -108,7 +107,7 @@
} }
], ],
"links": [], "links": [],
"modified": "2020-01-23 04:57:42.551355", "modified": "2020-07-08 11:02:32.660986",
"modified_by": "Administrator", "modified_by": "Administrator",
"module": "HR", "module": "HR",
"name": "Employee Checkin", "name": "Employee Checkin",

View File

@ -295,7 +295,7 @@ def make_bank_entry(dt, dn):
je = frappe.new_doc("Journal Entry") je = frappe.new_doc("Journal Entry")
je.voucher_type = 'Bank Entry' je.voucher_type = 'Bank Entry'
je.company = expense_claim.company je.company = expense_claim.company
je.remark = 'Payment against Expense Claim: ' + dn; je.remark = 'Payment against Expense Claim: ' + dn
je.append("accounts", { je.append("accounts", {
"account": expense_claim.payable_account, "account": expense_claim.payable_account,
@ -303,6 +303,7 @@ def make_bank_entry(dt, dn):
"reference_type": "Expense Claim", "reference_type": "Expense Claim",
"party_type": "Employee", "party_type": "Employee",
"party": expense_claim.employee, "party": expense_claim.employee,
"cost_center": erpnext.get_default_cost_center(expense_claim.company),
"reference_name": expense_claim.name "reference_name": expense_claim.name
}) })
@ -313,6 +314,7 @@ def make_bank_entry(dt, dn):
"reference_name": expense_claim.name, "reference_name": expense_claim.name,
"balance": default_bank_cash_account.balance, "balance": default_bank_cash_account.balance,
"account_currency": default_bank_cash_account.account_currency, "account_currency": default_bank_cash_account.account_currency,
"cost_center": erpnext.get_default_cost_center(expense_claim.company),
"account_type": default_bank_cash_account.account_type "account_type": default_bank_cash_account.account_type
}) })

View File

@ -44,7 +44,7 @@ class MaintenanceSchedule(TransactionBase):
for d in self.get('items'): for d in self.get('items'):
if d.serial_no: if d.serial_no:
serial_nos = get_valid_serial_nos(d.serial_no) serial_nos = get_valid_serial_nos(d.serial_no)
self.validate_serial_no(serial_nos, d.start_date) self.validate_serial_no(d.item_code, serial_nos, d.start_date)
self.update_amc_date(serial_nos, d.end_date) self.update_amc_date(serial_nos, d.end_date)
no_email_sp = [] no_email_sp = []
@ -178,14 +178,18 @@ class MaintenanceSchedule(TransactionBase):
serial_no_doc.amc_expiry_date = amc_expiry_date serial_no_doc.amc_expiry_date = amc_expiry_date
serial_no_doc.save() serial_no_doc.save()
def validate_serial_no(self, serial_nos, amc_start_date): def validate_serial_no(self, item_code, serial_nos, amc_start_date):
for serial_no in serial_nos: for serial_no in serial_nos:
sr_details = frappe.db.get_value("Serial No", serial_no, sr_details = frappe.db.get_value("Serial No", serial_no,
["warranty_expiry_date", "amc_expiry_date", "warehouse", "delivery_date"], as_dict=1) ["warranty_expiry_date", "amc_expiry_date", "warehouse", "delivery_date", "item_code"], as_dict=1)
if not sr_details: if not sr_details:
frappe.throw(_("Serial No {0} not found").format(serial_no)) frappe.throw(_("Serial No {0} not found").format(serial_no))
if sr_details.get("item_code") != item_code:
frappe.throw(_("Serial No {0} does not belong to Item {1}")
.format(frappe.bold(serial_no), frappe.bold(item_code)), title="Invalid")
if sr_details.warranty_expiry_date \ if sr_details.warranty_expiry_date \
and getdate(sr_details.warranty_expiry_date) >= getdate(amc_start_date): and getdate(sr_details.warranty_expiry_date) >= getdate(amc_start_date):
throw(_("Serial No {0} is under warranty upto {1}") throw(_("Serial No {0} is under warranty upto {1}")

View File

@ -701,7 +701,7 @@
"columns": 0, "columns": 0,
"default": "Draft", "default": "Draft",
"fieldname": "status", "fieldname": "status",
"fieldtype": "Data", "fieldtype": "Select",
"hidden": 0, "hidden": 0,
"ignore_user_permissions": 0, "ignore_user_permissions": 0,
"ignore_xss_filter": 0, "ignore_xss_filter": 0,
@ -1001,7 +1001,7 @@
"issingle": 0, "issingle": 0,
"istable": 0, "istable": 0,
"max_attachments": 0, "max_attachments": 0,
"modified": "2018-08-21 14:44:44.911402", "modified": "2020-07-15 14:44:44.911402",
"modified_by": "Administrator", "modified_by": "Administrator",
"module": "Maintenance", "module": "Maintenance",
"name": "Maintenance Visit", "name": "Maintenance Visit",

View File

@ -494,7 +494,7 @@ class BOM(WebsiteGenerator):
'image' : d.image, 'image' : d.image,
'stock_uom' : d.stock_uom, 'stock_uom' : d.stock_uom,
'stock_qty' : flt(d.stock_qty), 'stock_qty' : flt(d.stock_qty),
'rate' : d.base_rate, 'rate' : flt(d.base_rate) / flt(d.conversion_factor),
'include_item_in_manufacturing': d.include_item_in_manufacturing 'include_item_in_manufacturing': d.include_item_in_manufacturing
})) }))

View File

@ -697,6 +697,7 @@ execute:frappe.rename_doc("Desk Page", "Loan Management", "Loan", force=True)
erpnext.patches.v12_0.update_uom_conversion_factor erpnext.patches.v12_0.update_uom_conversion_factor
erpnext.patches.v13_0.delete_old_purchase_reports erpnext.patches.v13_0.delete_old_purchase_reports
erpnext.patches.v12_0.set_italian_import_supplier_invoice_permissions erpnext.patches.v12_0.set_italian_import_supplier_invoice_permissions
erpnext.patches.v12_0.unhide_cost_center_field
erpnext.patches.v13_0.update_sla_enhancements erpnext.patches.v13_0.update_sla_enhancements
erpnext.patches.v12_0.update_address_template_for_india erpnext.patches.v12_0.update_address_template_for_india
erpnext.patches.v13_0.update_deferred_settings erpnext.patches.v13_0.update_deferred_settings

View File

@ -0,0 +1,13 @@
# Copyright (c) 2017, Frappe and Contributors
# License: GNU General Public License v3. See license.txt
from __future__ import unicode_literals
import frappe
def execute():
frappe.db.sql("""
DELETE FROM `tabProperty Setter`
WHERE doc_type in ('Sales Invoice', 'Purchase Invoice', 'Payment Entry')
AND field_name = 'cost_center'
AND property = 'hidden'
""")

View File

@ -6,7 +6,6 @@ from __future__ import unicode_literals
import frappe import frappe
from frappe.utils import add_to_date from frappe.utils import add_to_date
from frappe.utils.dashboard import get_config, make_records
def execute(): def execute():
frappe.reload_doc("manufacturing", "doctype", "work_order") frappe.reload_doc("manufacturing", "doctype", "work_order")

View File

@ -8,8 +8,7 @@ frappe.ui.form.on('Additional Salary', {
frm.set_query("employee", function() { frm.set_query("employee", function() {
return { return {
filters: { filters: {
company: frm.doc.company, company: frm.doc.company
status: "Active"
} }
}; };
}); });

View File

@ -33,12 +33,16 @@ class AdditionalSalary(Document):
frappe.throw(_("From Date can not be greater than To Date.")) frappe.throw(_("From Date can not be greater than To Date."))
if date_of_joining: if date_of_joining:
if getdate(self.payroll_date) < getdate(date_of_joining): if self.payroll_date and getdate(self.payroll_date) < getdate(date_of_joining):
frappe.throw(_("Payroll date can not be less than employee's joining date.")) frappe.throw(_("Payroll date can not be less than employee's joining date."))
elif getdate(self.from_date) < getdate(date_of_joining): elif self.from_date and getdate(self.from_date) < getdate(date_of_joining):
frappe.throw(_("From date can not be less than employee's joining date.")) frappe.throw(_("From date can not be less than employee's joining date."))
elif relieving_date and getdate(self.to_date) > getdate(relieving_date):
if relieving_date:
if self.to_date and getdate(self.to_date) > getdate(relieving_date):
frappe.throw(_("To date can not be greater than employee's relieving date.")) frappe.throw(_("To date can not be greater than employee's relieving date."))
if self.payroll_date and getdate(self.payroll_date) > getdate(relieving_date):
frappe.throw(_("Payroll date can not be greater than employee's relieving date."))
def get_amount(self, sal_start_date, sal_end_date): def get_amount(self, sal_start_date, sal_end_date):
start_date = getdate(sal_start_date) start_date = getdate(sal_start_date)

View File

@ -7,7 +7,7 @@ import frappe, unittest
test_records = frappe.get_test_records('Project') test_records = frappe.get_test_records('Project')
test_ignore = ["Sales Order"] test_ignore = ["Sales Order"]
from erpnext.projects.doctype.project_template.test_project_template import get_project_template from erpnext.projects.doctype.project_template.test_project_template import get_project_template, make_project_template
from erpnext.projects.doctype.project.project import set_project_status from erpnext.projects.doctype.project.project import set_project_status
from frappe.utils import getdate from frappe.utils import getdate
@ -44,3 +44,23 @@ def get_project(name):
)).insert() )).insert()
return project return project
def make_project(args):
args = frappe._dict(args)
if args.project_template_name:
template = make_project_template(args.project_template_name)
else:
template = get_project_template()
project = frappe.get_doc(dict(
doctype = 'Project',
project_name = args.project_name,
status = 'Open',
project_template = template.name,
expected_start_date = args.start_date
))
if not frappe.db.exists("Project", args.project_name):
project.insert()
return project

View File

@ -27,3 +27,22 @@ def get_project_template():
)).insert() )).insert()
return frappe.get_doc('Project Template', 'Test Project Template') return frappe.get_doc('Project Template', 'Test Project Template')
def make_project_template(project_template_name, project_tasks=[]):
if not frappe.db.exists('Project Template', project_template_name):
frappe.get_doc(dict(
doctype = 'Project Template',
name = project_template_name,
tasks = project_tasks or [
dict(subject='Task 1', description='Task 1 description',
start=0, duration=3),
dict(subject='Task 2', description='Task 2 description',
start=0, duration=2),
dict(subject='Task 3', description='Task 3 description',
start=2, duration=4),
dict(subject='Task 4', description='Task 4 description',
start=3, duration=2),
]
)).insert()
return frappe.get_doc('Project Template', project_template_name)

View File

@ -9,7 +9,7 @@ import frappe
from frappe import _, throw from frappe import _, throw
from frappe.desk.form.assign_to import clear, close_all_assignments from frappe.desk.form.assign_to import clear, close_all_assignments
from frappe.model.mapper import get_mapped_doc from frappe.model.mapper import get_mapped_doc
from frappe.utils import add_days, cstr, date_diff, get_link_to_form, getdate, today from frappe.utils import add_days, cstr, date_diff, get_link_to_form, getdate, today, flt
from frappe.utils.nestedset import NestedSet from frappe.utils.nestedset import NestedSet
@ -63,10 +63,10 @@ class Task(NestedSet):
close_all_assignments(self.doctype, self.name) close_all_assignments(self.doctype, self.name)
def validate_progress(self): def validate_progress(self):
if (self.progress or 0) > 100: if flt(self.progress or 0) > 100:
frappe.throw(_("Progress % for a task cannot be more than 100.")) frappe.throw(_("Progress % for a task cannot be more than 100."))
if self.progress == 100: if flt(self.progress) == 100:
self.status = 'Completed' self.status = 'Completed'
if self.status == 'Completed': if self.status == 'Completed':

View File

@ -450,7 +450,7 @@ frappe.help.help_links['Form/Opportunity'] = [
] ]
frappe.help.help_links['Form/Address'] = [ frappe.help.help_links['Form/Address'] = [
{ label: 'Address', url: docsUrl + 'user/manual/en/CRM/contact' }, { label: 'Address', url: docsUrl + 'user/manual/en/CRM/address' },
] ]
frappe.help.help_links['Form/Contact'] = [ frappe.help.help_links['Form/Contact'] = [

View File

@ -3,6 +3,7 @@
frappe.ui.form.on('GSTR 3B Report', { frappe.ui.form.on('GSTR 3B Report', {
refresh : function(frm) { refresh : function(frm) {
frm.doc.__unsaved = 1;
if(!frm.is_new()) { if(!frm.is_new()) {
frm.set_intro(__("Please save the report again to rebuild or update")); frm.set_intro(__("Please save the report again to rebuild or update"));
frm.add_custom_button(__('Download JSON'), function() { frm.add_custom_button(__('Download JSON'), function() {

View File

@ -243,20 +243,15 @@ class GSTR3BReport(Document):
osup_det = self.report_dict["sup_details"]["osup_det"] osup_det = self.report_dict["sup_details"]["osup_det"]
for d in inter_state_supply.get("Unregistered", []): for key, value in iteritems(inter_state_supply):
self.report_dict["inter_sup"]["unreg_details"].append(d) if key[0] == "Unregistered":
osup_det["txval"] = flt(osup_det["txval"] + d["txval"], 2) self.report_dict["inter_sup"]["unreg_details"].append(value)
osup_det["iamt"] = flt(osup_det["iamt"] + d["iamt"], 2)
for d in inter_state_supply.get("Registered Composition", []): if key[0] == "Registered Composition":
self.report_dict["inter_sup"]["comp_details"].append(d) self.report_dict["inter_sup"]["comp_details"].append(value)
osup_det["txval"] = flt(osup_det["txval"] + d["txval"], 2)
osup_det["iamt"] = flt(osup_det["iamt"] + d["iamt"], 2)
for d in inter_state_supply.get("UIN Holders", []): if key[0] == "UIN Holders":
self.report_dict["inter_sup"]["uin_details"].append(d) self.report_dict["inter_sup"]["uin_details"].append(value)
osup_det["txval"] = flt(osup_det["txval"] + d["txval"], 2)
osup_det["iamt"] = flt(osup_det["iamt"] + d["iamt"], 2)
def get_total_taxable_value(self, doctype, reverse_charge): def get_total_taxable_value(self, doctype, reverse_charge):
@ -301,41 +296,55 @@ class GSTR3BReport(Document):
(self.month_no, self.year, self.company, self.gst_details.get("gstin")), as_dict=1)[0].total (self.month_no, self.year, self.company, self.gst_details.get("gstin")), as_dict=1)[0].total
def get_inter_state_supplies(self, state_number): def get_inter_state_supplies(self, state_number):
inter_state_supply_tax = frappe.db.sql(""" select t.account_head, t.tax_amount_after_discount_amount as tax_amount,
inter_state_supply_taxable_value = frappe.db.sql(""" select sum(s.net_total) as total, s.place_of_supply, s.gst_category s.name, s.net_total, s.place_of_supply, s.gst_category from `tabSales Invoice` s, `tabSales Taxes and Charges` t
from `tabSales Invoice` s where s.docstatus = 1 and month(s.posting_date) = %s and year(s.posting_date) = %s
and s.company = %s and s.company_gstin = %s and s.gst_category in ('Unregistered', 'Registered Composition', 'UIN Holders')
group by s.gst_category, s.place_of_supply""", (self.month_no, self.year, self.company, self.gst_details.get("gstin")), as_dict=1)
inter_state_supply_tax = frappe.db.sql(""" select sum(t.tax_amount_after_discount_amount) as tax_amount, s.place_of_supply, s.gst_category
from `tabSales Invoice` s, `tabSales Taxes and Charges` t
where t.parent = s.name and s.docstatus = 1 and month(s.posting_date) = %s and year(s.posting_date) = %s where t.parent = s.name and s.docstatus = 1 and month(s.posting_date) = %s and year(s.posting_date) = %s
and s.company = %s and s.company_gstin = %s and s.gst_category in ('Unregistered', 'Registered Composition', 'UIN Holders') and s.company = %s and s.company_gstin = %s and s.gst_category in ('Unregistered', 'Registered Composition', 'UIN Holders')
group by s.gst_category, s.place_of_supply""", (self.month_no, self.year, self.company, self.gst_details.get("gstin")), as_dict=1) """, (self.month_no, self.year, self.company, self.gst_details.get("gstin")), as_dict=1)
inter_state_supply_tax_mapping = {} inter_state_supply_tax_mapping = {}
inter_state_supply_details = {} inter_state_supply_details = {}
for d in inter_state_supply_tax: for d in inter_state_supply_tax:
inter_state_supply_tax_mapping.setdefault(d.place_of_supply, d.tax_amount) inter_state_supply_tax_mapping.setdefault(d.name, {
'place_of_supply': d.place_of_supply,
for d in inter_state_supply_taxable_value: 'taxable_value': d.net_total,
inter_state_supply_details.setdefault( 'camt': 0.0,
d.gst_category, [] 'samt': 0.0,
) 'iamt': 0.0,
'csamt': 0.0
if d.place_of_supply:
if state_number != d.place_of_supply.split("-")[0]:
inter_state_supply_details[d.gst_category].append({
"pos": d.place_of_supply.split("-")[0],
"txval": flt(d.total, 2),
"iamt": flt(inter_state_supply_tax_mapping.get(d.place_of_supply), 2)
}) })
else:
if d.account_head in [d.cgst_account for d in self.account_heads]:
inter_state_supply_tax_mapping[d.name]['camt'] += d.tax_amount
if d.account_head in [d.sgst_account for d in self.account_heads]:
inter_state_supply_tax_mapping[d.name]['samt'] += d.tax_amount
if d.account_head in [d.igst_account for d in self.account_heads]:
inter_state_supply_tax_mapping[d.name]['iamt'] += d.tax_amount
if d.account_head in [d.cess_account for d in self.account_heads]:
inter_state_supply_tax_mapping[d.name]['csamt'] += d.tax_amount
for key, value in iteritems(inter_state_supply_tax_mapping):
if d.place_of_supply:
osup_det = self.report_dict["sup_details"]["osup_det"] osup_det = self.report_dict["sup_details"]["osup_det"]
osup_det["txval"] = flt(osup_det["txval"] + d.total, 2) osup_det["txval"] = flt(osup_det["txval"] + value['taxable_value'], 2)
osup_det["camt"] = flt(osup_det["camt"] + inter_state_supply_tax_mapping.get(d.place_of_supply)/2, 2) osup_det["iamt"] = flt(osup_det["iamt"] + value['iamt'], 2)
osup_det["samt"] = flt(osup_det["samt"] + inter_state_supply_tax_mapping.get(d.place_of_supply)/2, 2) osup_det["camt"] = flt(osup_det["camt"] + value['camt'], 2)
osup_det["samt"] = flt(osup_det["samt"] + value['samt'], 2)
osup_det["csamt"] = flt(osup_det["csamt"] + value['csamt'], 2)
if state_number != d.place_of_supply.split("-")[0]:
inter_state_supply_details.setdefault((d.gst_category, d.place_of_supply), {
"txval": 0.0,
"pos": d.place_of_supply.split("-")[0],
"iamt": 0.0
})
inter_state_supply_details[(d.gst_category, d.place_of_supply)]['txval'] += value['taxable_value']
inter_state_supply_details[(d.gst_category, d.place_of_supply)]['iamt'] += value['iamt']
return inter_state_supply_details return inter_state_supply_details

View File

@ -1,7 +1,7 @@
from __future__ import unicode_literals from __future__ import unicode_literals
import frappe, re, json import frappe, re, json
from frappe import _ from frappe import _
from frappe.utils import cstr, flt, date_diff, nowdate from frappe.utils import cstr, flt, date_diff, nowdate, round_based_on_smallest_currency_fraction, money_in_words
from erpnext.regional.india import states, state_numbers from erpnext.regional.india import states, state_numbers
from erpnext.controllers.taxes_and_totals import get_itemised_tax, get_itemised_taxable_amount from erpnext.controllers.taxes_and_totals import get_itemised_tax, get_itemised_taxable_amount
from erpnext.controllers.accounts_controller import get_taxes_and_charges from erpnext.controllers.accounts_controller import get_taxes_and_charges
@ -648,6 +648,7 @@ def validate_state_code(state_code, address):
else: else:
return int(state_code) return int(state_code)
@frappe.whitelist()
def get_gst_accounts(company, account_wise=False): def get_gst_accounts(company, account_wise=False):
gst_accounts = frappe._dict() gst_accounts = frappe._dict()
gst_settings_accounts = frappe.get_all("GST Account", gst_settings_accounts = frappe.get_all("GST Account",
@ -666,14 +667,55 @@ def get_gst_accounts(company, account_wise=False):
return gst_accounts return gst_accounts
def make_reverse_charge_entries(doc, method): def update_grand_total_for_rcm(doc, method):
country = frappe.get_cached_value('Company', doc.company, 'country')
if country != 'India':
return
if doc.reverse_charge == 'Y':
gst_accounts = get_gst_accounts(doc.company)
gst_account_list = gst_accounts.get('cgst_account') + gst_accounts.get('sgst_account') \
+ gst_accounts.get('igst_account')
gst_tax = 0
for tax in doc.get('taxes'):
if tax.category not in ("Total", "Valuation and Total"):
continue
if flt(tax.base_tax_amount_after_discount_amount) and tax.account_head in gst_account_list:
gst_tax += tax.base_tax_amount_after_discount_amount
doc.taxes_and_charges_added -= gst_tax
doc.total_taxes_and_charges -= gst_tax
update_totals(gst_tax, doc)
def update_totals(gst_tax, doc):
doc.grand_total -= gst_tax
if doc.meta.get_field("rounded_total"):
if doc.is_rounded_total_disabled():
doc.outstanding_amount = doc.grand_total
else:
doc.rounded_total = round_based_on_smallest_currency_fraction(doc.grand_total,
doc.currency, doc.precision("rounded_total"))
doc.rounding_adjustment += flt(doc.rounded_total - doc.grand_total,
doc.precision("rounding_adjustment"))
doc.outstanding_amount = doc.rounded_total or doc.grand_total
doc.in_words = money_in_words(doc.grand_total, doc.currency)
doc.set_payment_schedule()
def make_regional_gl_entries(gl_entries, doc):
country = frappe.get_cached_value('Company', doc.company, 'country') country = frappe.get_cached_value('Company', doc.company, 'country')
if country != 'India': if country != 'India':
return return
if doc.reverse_charge == 'Y': if doc.reverse_charge == 'Y':
gl_entries = []
gst_accounts = get_gst_accounts(doc.company) gst_accounts = get_gst_accounts(doc.company)
gst_account_list = gst_accounts.get('cgst_account') + gst_accounts.get('sgst_account') \ gst_account_list = gst_accounts.get('cgst_account') + gst_accounts.get('sgst_account') \
+ gst_accounts.get('igst_account') + gst_accounts.get('igst_account')
@ -698,19 +740,4 @@ def make_reverse_charge_entries(doc, method):
}, account_currency, item=tax) }, account_currency, item=tax)
) )
gl_entries.append(doc.get_gl_dict( return gl_entries
{
"account": doc.credit_to if doc.doctype == 'Purchase Invoice' else doc.debit_to,
"cost_center": doc.cost_center,
"posting_date": doc.posting_date,
"party_type": 'Supplier',
"party": doc.supplier,
"against": tax.account_head,
"debit": tax.base_tax_amount_after_discount_amount,
"debit_in_account_currency": tax.base_tax_amount_after_discount_amount \
if account_currency==doc.company_currency \
else tax.tax_amount_after_discount_amount
}, account_currency, item=doc)
)
make_gl_entries(gl_entries)

View File

@ -186,9 +186,12 @@ class TestDatev(TestCase):
"charge_type": "On Net Total", "charge_type": "On Net Total",
"account_head": tax_account, "account_head": tax_account,
"description": "Umsatzsteuer 19 %", "description": "Umsatzsteuer 19 %",
"rate": 19 "rate": 19,
"cost_center": self.company.cost_center
}) })
si.cost_center = self.company.cost_center
si.save() si.save()
si.submit() si.submit()

View File

@ -118,7 +118,7 @@ class Gstr1Report(object):
row.append(invoice_details.get(fieldname)) row.append(invoice_details.get(fieldname))
taxable_value = 0 taxable_value = 0
if invoice in self.cgst_igst_invoices: if invoice in self.cgst_sgst_invoices:
division_factor = 2 division_factor = 2
else: else:
division_factor = 1 division_factor = 1
@ -129,6 +129,8 @@ class Gstr1Report(object):
taxable_value += abs(net_amount) taxable_value += abs(net_amount)
elif not self.item_tax_rate.get(invoice): elif not self.item_tax_rate.get(invoice):
taxable_value += abs(net_amount) taxable_value += abs(net_amount)
elif tax_rate:
taxable_value += abs(net_amount)
row += [tax_rate or 0, taxable_value] row += [tax_rate or 0, taxable_value]
@ -227,7 +229,7 @@ class Gstr1Report(object):
self.items_based_on_tax_rate = {} self.items_based_on_tax_rate = {}
self.invoice_cess = frappe._dict() self.invoice_cess = frappe._dict()
self.cgst_igst_invoices = [] self.cgst_sgst_invoices = []
unidentified_gst_accounts = [] unidentified_gst_accounts = []
for parent, account, item_wise_tax_detail, tax_amount in self.tax_details: for parent, account, item_wise_tax_detail, tax_amount in self.tax_details:
@ -251,8 +253,8 @@ class Gstr1Report(object):
tax_rate = tax_amounts[0] tax_rate = tax_amounts[0]
if cgst_or_sgst: if cgst_or_sgst:
tax_rate *= 2 tax_rate *= 2
if parent not in self.cgst_igst_invoices: if parent not in self.cgst_sgst_invoices:
self.cgst_igst_invoices.append(parent) self.cgst_sgst_invoices.append(parent)
rate_based_dict = self.items_based_on_tax_rate\ rate_based_dict = self.items_based_on_tax_rate\
.setdefault(parent, {}).setdefault(tax_rate, []) .setdefault(parent, {}).setdefault(tax_rate, [])

View File

@ -44,6 +44,7 @@ class Gstr2Report(Gstr1Report):
for inv, items_based_on_rate in self.items_based_on_tax_rate.items(): for inv, items_based_on_rate in self.items_based_on_tax_rate.items():
invoice_details = self.invoices.get(inv) invoice_details = self.invoices.get(inv)
for rate, items in items_based_on_rate.items(): for rate, items in items_based_on_rate.items():
if rate:
if inv not in self.igst_invoices: if inv not in self.igst_invoices:
rate = rate / 2 rate = rate / 2
row, taxable_value = self.get_row_data_for_invoice(inv, invoice_details, rate, items) row, taxable_value = self.get_row_data_for_invoice(inv, invoice_details, rate, items)
@ -54,7 +55,6 @@ class Gstr2Report(Gstr1Report):
tax_amount = taxable_value * rate / 100 tax_amount = taxable_value * rate / 100
row += [tax_amount, 0, 0] row += [tax_amount, 0, 0]
row += [ row += [
self.invoice_cess.get(inv), self.invoice_cess.get(inv),
invoice_details.get('eligibility_for_itc'), invoice_details.get('eligibility_for_itc'),
@ -86,7 +86,7 @@ class Gstr2Report(Gstr1Report):
conditions += opts[1] conditions += opts[1]
if self.filters.get("type_of_business") == "B2B": if self.filters.get("type_of_business") == "B2B":
conditions += "and ifnull(gst_category, '') != 'Overseas' and is_return != 1 " conditions += "and ifnull(gst_category, '') in ('Registered Regular', 'Deemed Export', 'SEZ') and is_return != 1 "
elif self.filters.get("type_of_business") == "CDNR": elif self.filters.get("type_of_business") == "CDNR":
conditions += """ and is_return = 1 """ conditions += """ and is_return = 1 """

View File

@ -3,6 +3,7 @@ frappe.listview_settings['Quotation'] = {
"company", "currency", 'valid_till'], "company", "currency", 'valid_till'],
onload: function(listview) { onload: function(listview) {
if (listview.page.fields_dict.quotation_to) {
listview.page.fields_dict.quotation_to.get_query = function() { listview.page.fields_dict.quotation_to.get_query = function() {
return { return {
"filters": { "filters": {
@ -10,6 +11,7 @@ frappe.listview_settings['Quotation'] = {
} }
}; };
}; };
}
}, },
get_indicator: function(doc) { get_indicator: function(doc) {

View File

@ -143,7 +143,7 @@ class Batch(Document):
@frappe.whitelist() @frappe.whitelist()
def get_batch_qty(batch_no=None, warehouse=None, item_code=None): def get_batch_qty(batch_no=None, warehouse=None, item_code=None, posting_date=None, posting_time=None):
"""Returns batch actual qty if warehouse is passed, """Returns batch actual qty if warehouse is passed,
or returns dict of qty by warehouse if warehouse is None or returns dict of qty by warehouse if warehouse is None
@ -155,9 +155,14 @@ def get_batch_qty(batch_no=None, warehouse=None, item_code=None):
out = 0 out = 0
if batch_no and warehouse: if batch_no and warehouse:
cond = ""
if posting_date and posting_time:
cond = " and timestamp(posting_date, posting_time) <= timestamp('{0}', '{1}')".format(posting_date,
posting_time)
out = float(frappe.db.sql("""select sum(actual_qty) out = float(frappe.db.sql("""select sum(actual_qty)
from `tabStock Ledger Entry` from `tabStock Ledger Entry`
where warehouse=%s and batch_no=%s""", where warehouse=%s and batch_no=%s {0}""".format(cond),
(warehouse, batch_no))[0][0] or 0) (warehouse, batch_no))[0][0] or 0)
if batch_no and not warehouse: if batch_no and not warehouse:

View File

@ -537,11 +537,8 @@ class TestDeliveryNote(unittest.TestCase):
dt = make_delivery_trip(dn.name) dt = make_delivery_trip(dn.name)
self.assertEqual(dn.name, dt.delivery_stops[0].delivery_note) self.assertEqual(dn.name, dt.delivery_stops[0].delivery_note)
def test_delivery_note_for_enable_allow_cost_center_in_entry_of_bs_account(self): def test_delivery_note_with_cost_center(self):
from erpnext.accounts.doctype.cost_center.test_cost_center import create_cost_center from erpnext.accounts.doctype.cost_center.test_cost_center import create_cost_center
accounts_settings = frappe.get_doc('Accounts Settings', 'Accounts Settings')
accounts_settings.allow_cost_center_in_entry_of_bs_account = 1
accounts_settings.save()
cost_center = "_Test Cost Center for BS Account - TCP1" cost_center = "_Test Cost Center for BS Account - TCP1"
create_cost_center(cost_center_name="_Test Cost Center for BS Account", company="_Test Company with perpetual inventory") create_cost_center(cost_center_name="_Test Cost Center for BS Account", company="_Test Company with perpetual inventory")
@ -567,13 +564,8 @@ class TestDeliveryNote(unittest.TestCase):
} }
for i, gle in enumerate(gl_entries): for i, gle in enumerate(gl_entries):
self.assertEqual(expected_values[gle.account]["cost_center"], gle.cost_center) self.assertEqual(expected_values[gle.account]["cost_center"], gle.cost_center)
accounts_settings.allow_cost_center_in_entry_of_bs_account = 0
accounts_settings.save()
def test_delivery_note_for_disable_allow_cost_center_in_entry_of_bs_account(self): def test_delivery_note_cost_center_with_balance_sheet_account(self):
accounts_settings = frappe.get_doc('Accounts Settings', 'Accounts Settings')
accounts_settings.allow_cost_center_in_entry_of_bs_account = 0
accounts_settings.save()
cost_center = "Main - TCP1" cost_center = "Main - TCP1"
company = frappe.db.get_value('Warehouse', 'Stores - TCP1', 'company') company = frappe.db.get_value('Warehouse', 'Stores - TCP1', 'company')
@ -583,7 +575,11 @@ class TestDeliveryNote(unittest.TestCase):
make_stock_entry(target="Stores - TCP1", qty=5, basic_rate=100) make_stock_entry(target="Stores - TCP1", qty=5, basic_rate=100)
stock_in_hand_account = get_inventory_account('_Test Company with perpetual inventory') stock_in_hand_account = get_inventory_account('_Test Company with perpetual inventory')
dn = create_delivery_note(company='_Test Company with perpetual inventory', warehouse='Stores - TCP1', cost_center = 'Main - TCP1', expense_account = "Cost of Goods Sold - TCP1") dn = create_delivery_note(company='_Test Company with perpetual inventory', warehouse='Stores - TCP1', cost_center = 'Main - TCP1', expense_account = "Cost of Goods Sold - TCP1",
do_not_submit=1)
dn.get('items')[0].cost_center = None
dn.submit()
gl_entries = get_gl_entries("Delivery Note", dn.name) gl_entries = get_gl_entries("Delivery Note", dn.name)
@ -593,7 +589,7 @@ class TestDeliveryNote(unittest.TestCase):
"cost_center": cost_center "cost_center": cost_center
}, },
stock_in_hand_account: { stock_in_hand_account: {
"cost_center": None "cost_center": cost_center
} }
} }
for i, gle in enumerate(gl_entries): for i, gle in enumerate(gl_entries):

View File

@ -1,5 +1,4 @@
{ {
"actions": [],
"autoname": "hash", "autoname": "hash",
"creation": "2013-04-22 13:15:44", "creation": "2013-04-22 13:15:44",
"doctype": "DocType", "doctype": "DocType",
@ -82,6 +81,7 @@
"accounting_dimensions_section", "accounting_dimensions_section",
"cost_center", "cost_center",
"dimension_col_break", "dimension_col_break",
"project",
"section_break_72", "section_break_72",
"page_break" "page_break"
], ],
@ -701,6 +701,12 @@
"fieldname": "dimension_col_break", "fieldname": "dimension_col_break",
"fieldtype": "Column Break" "fieldtype": "Column Break"
}, },
{
"fieldname": "project",
"fieldtype": "Link",
"label": "Project",
"options": "Project"
},
{ {
"fieldname": "dn_detail", "fieldname": "dn_detail",
"fieldtype": "Data", "fieldtype": "Data",
@ -714,7 +720,7 @@
"idx": 1, "idx": 1,
"istable": 1, "istable": 1,
"links": [], "links": [],
"modified": "2020-03-05 14:18:33.131672", "modified": "2020-07-20 12:25:06.177894",
"modified_by": "Administrator", "modified_by": "Administrator",
"module": "Stock", "module": "Stock",
"name": "Delivery Note Item", "name": "Delivery Note Item",

View File

@ -180,9 +180,8 @@ frappe.ui.form.on('Material Request', {
}); });
}, },
get_item_data: function(frm, item) { get_item_data: function(frm, item, overwrite_warehouse=false) {
if (item && !item.item_code) { return; } if (item && !item.item_code) { return; }
frm.call({ frm.call({
method: "erpnext.stock.get_item_details.get_item_details", method: "erpnext.stock.get_item_details.get_item_details",
child: item, child: item,
@ -203,7 +202,8 @@ frappe.ui.form.on('Material Request', {
plc_conversion_rate: 1, plc_conversion_rate: 1,
rate: item.rate, rate: item.rate,
conversion_factor: item.conversion_factor conversion_factor: item.conversion_factor
} },
overwrite_warehouse: overwrite_warehouse
}, },
callback: function(r) { callback: function(r) {
const d = item; const d = item;
@ -354,29 +354,29 @@ frappe.ui.form.on("Material Request Item", {
} }
const item = locals[doctype][name]; const item = locals[doctype][name];
frm.events.get_item_data(frm, item); frm.events.get_item_data(frm, item, false);
}, },
from_warehouse: function(frm, doctype, name) { from_warehouse: function(frm, doctype, name) {
const item = locals[doctype][name]; const item = locals[doctype][name];
frm.events.get_item_data(frm, item); frm.events.get_item_data(frm, item, false);
}, },
warehouse: function(frm, doctype, name) { warehouse: function(frm, doctype, name) {
const item = locals[doctype][name]; const item = locals[doctype][name];
frm.events.get_item_data(frm, item); frm.events.get_item_data(frm, item, false);
}, },
rate: function(frm, doctype, name) { rate: function(frm, doctype, name) {
const item = locals[doctype][name]; const item = locals[doctype][name];
frm.events.get_item_data(frm, item); frm.events.get_item_data(frm, item, false);
}, },
item_code: function(frm, doctype, name) { item_code: function(frm, doctype, name) {
const item = locals[doctype][name]; const item = locals[doctype][name];
item.rate = 0; item.rate = 0;
set_schedule_date(frm); set_schedule_date(frm);
frm.events.get_item_data(frm, item); frm.events.get_item_data(frm, item, true);
}, },
schedule_date: function(frm, cdt, cdn) { schedule_date: function(frm, cdt, cdn) {

File diff suppressed because it is too large Load Diff

View File

@ -403,11 +403,8 @@ class TestPurchaseReceipt(unittest.TestCase):
pr_return.submit() pr_return.submit()
def test_purchase_receipt_for_enable_allow_cost_center_in_entry_of_bs_account(self): def test_purchase_receipt_cost_center(self):
from erpnext.accounts.doctype.cost_center.test_cost_center import create_cost_center from erpnext.accounts.doctype.cost_center.test_cost_center import create_cost_center
accounts_settings = frappe.get_doc('Accounts Settings', 'Accounts Settings')
accounts_settings.allow_cost_center_in_entry_of_bs_account = 1
accounts_settings.save()
cost_center = "_Test Cost Center for BS Account - TCP1" cost_center = "_Test Cost Center for BS Account - TCP1"
create_cost_center(cost_center_name="_Test Cost Center for BS Account", company="_Test Company with perpetual inventory") create_cost_center(cost_center_name="_Test Cost Center for BS Account", company="_Test Company with perpetual inventory")
@ -435,14 +432,7 @@ class TestPurchaseReceipt(unittest.TestCase):
for i, gle in enumerate(gl_entries): for i, gle in enumerate(gl_entries):
self.assertEqual(expected_values[gle.account]["cost_center"], gle.cost_center) self.assertEqual(expected_values[gle.account]["cost_center"], gle.cost_center)
accounts_settings.allow_cost_center_in_entry_of_bs_account = 0 def test_purchase_receipt_cost_center_with_balance_sheet_account(self):
accounts_settings.save()
def test_purchase_receipt_for_disable_allow_cost_center_in_entry_of_bs_account(self):
accounts_settings = frappe.get_doc('Accounts Settings', 'Accounts Settings')
accounts_settings.allow_cost_center_in_entry_of_bs_account = 0
accounts_settings.save()
if not frappe.db.exists('Location', 'Test Location'): if not frappe.db.exists('Location', 'Test Location'):
frappe.get_doc({ frappe.get_doc({
'doctype': 'Location', 'doctype': 'Location',
@ -454,13 +444,14 @@ class TestPurchaseReceipt(unittest.TestCase):
gl_entries = get_gl_entries("Purchase Receipt", pr.name) gl_entries = get_gl_entries("Purchase Receipt", pr.name)
self.assertTrue(gl_entries) self.assertTrue(gl_entries)
cost_center = pr.get('items')[0].cost_center
expected_values = { expected_values = {
"Stock Received But Not Billed - TCP1": { "Stock Received But Not Billed - TCP1": {
"cost_center": None "cost_center": cost_center
}, },
stock_in_hand_account: { stock_in_hand_account: {
"cost_center": None "cost_center": cost_center
} }
} }
for i, gle in enumerate(gl_entries): for i, gle in enumerate(gl_entries):

View File

@ -74,6 +74,20 @@ frappe.ui.form.on("Stock Reconciliation", {
, __("Get Items"), __("Update")); , __("Get Items"), __("Update"));
}, },
posting_date: function(frm) {
frm.trigger("set_valuation_rate_and_qty_for_all_items");
},
posting_time: function(frm) {
frm.trigger("set_valuation_rate_and_qty_for_all_items");
},
set_valuation_rate_and_qty_for_all_items: function(frm) {
frm.doc.items.forEach(row => {
frm.events.set_valuation_rate_and_qty(frm, row.doctype, row.name);
});
},
set_valuation_rate_and_qty: function(frm, cdt, cdn) { set_valuation_rate_and_qty: function(frm, cdt, cdn) {
var d = frappe.model.get_doc(cdt, cdn); var d = frappe.model.get_doc(cdt, cdn);

View File

@ -184,8 +184,12 @@ class StockReconciliation(StockController):
sl_entries = [] sl_entries = []
has_serial_no = False has_serial_no = False
has_batch_no = False
for row in self.items: for row in self.items:
item = frappe.get_doc("Item", row.item_code) item = frappe.get_doc("Item", row.item_code)
if item.has_batch_no:
has_batch_no = True
if item.has_serial_no or item.has_batch_no: if item.has_serial_no or item.has_batch_no:
has_serial_no = True has_serial_no = True
self.get_sle_for_serialized_items(row, sl_entries) self.get_sle_for_serialized_items(row, sl_entries)
@ -222,7 +226,11 @@ class StockReconciliation(StockController):
if has_serial_no: if has_serial_no:
sl_entries = self.merge_similar_item_serial_nos(sl_entries) sl_entries = self.merge_similar_item_serial_nos(sl_entries)
self.make_sl_entries(sl_entries) allow_negative_stock = False
if has_batch_no:
allow_negative_stock = True
self.make_sl_entries(sl_entries, allow_negative_stock=allow_negative_stock)
if has_serial_no and sl_entries: if has_serial_no and sl_entries:
self.update_valuation_rate_for_serial_no() self.update_valuation_rate_for_serial_no()
@ -493,7 +501,7 @@ def get_stock_balance_for(item_code, warehouse,
qty, rate = data qty, rate = data
if item_dict.get("has_batch_no"): if item_dict.get("has_batch_no"):
qty = get_batch_qty(batch_no, warehouse) or 0 qty = get_batch_qty(batch_no, warehouse, posting_date=posting_date, posting_time=posting_time) or 0
return { return {
'qty': qty, 'qty': qty,

View File

@ -47,6 +47,8 @@ def get_item_details(args, doc=None, for_validate=False, overwrite_warehouse=Tru
""" """
args = process_args(args) args = process_args(args)
for_validate = process_string_args(for_validate)
overwrite_warehouse = process_string_args(overwrite_warehouse)
item = frappe.get_cached_doc("Item", args.item_code) item = frappe.get_cached_doc("Item", args.item_code)
validate_item_details(args, item) validate_item_details(args, item)
@ -166,6 +168,10 @@ def process_args(args):
set_transaction_type(args) set_transaction_type(args)
return args return args
def process_string_args(args):
if isinstance(args, string_types):
args = json.loads(args)
return args
@frappe.whitelist() @frappe.whitelist()
def get_item_code(barcode=None, serial_no=None): def get_item_code(barcode=None, serial_no=None):

View File

@ -2,7 +2,7 @@
# License: GNU General Public License v3. See license.txt # License: GNU General Public License v3. See license.txt
from __future__ import unicode_literals from __future__ import unicode_literals
import frappe import frappe, erpnext
from frappe import _ from frappe import _
from frappe.utils import flt, cint, getdate, now, date_diff from frappe.utils import flt, cint, getdate, now, date_diff
from erpnext.stock.utils import add_additional_uom_columns from erpnext.stock.utils import add_additional_uom_columns
@ -20,6 +20,11 @@ def execute(filters=None):
from_date = filters.get('from_date') from_date = filters.get('from_date')
to_date = filters.get('to_date') to_date = filters.get('to_date')
if filters.get("company"):
company_currency = erpnext.get_company_currency(filters.get("company"))
else:
company_currency = frappe.db.get_single_value("Global Defaults", "default_currency")
include_uom = filters.get("include_uom") include_uom = filters.get("include_uom")
columns = get_columns(filters) columns = get_columns(filters)
items = get_items(filters) items = get_items(filters)
@ -52,6 +57,7 @@ def execute(filters=None):
item_reorder_qty = item_reorder_detail_map[item + warehouse]["warehouse_reorder_qty"] item_reorder_qty = item_reorder_detail_map[item + warehouse]["warehouse_reorder_qty"]
report_data = { report_data = {
'currency': company_currency,
'item_code': item, 'item_code': item,
'warehouse': warehouse, 'warehouse': warehouse,
'company': company, 'company': company,
@ -89,7 +95,6 @@ def execute(filters=None):
def get_columns(filters): def get_columns(filters):
"""return columns""" """return columns"""
columns = [ columns = [
{"label": _("Item"), "fieldname": "item_code", "fieldtype": "Link", "options": "Item", "width": 100}, {"label": _("Item"), "fieldname": "item_code", "fieldtype": "Link", "options": "Item", "width": 100},
{"label": _("Item Name"), "fieldname": "item_name", "width": 150}, {"label": _("Item Name"), "fieldname": "item_name", "width": 150},
@ -97,14 +102,14 @@ def get_columns(filters):
{"label": _("Warehouse"), "fieldname": "warehouse", "fieldtype": "Link", "options": "Warehouse", "width": 100}, {"label": _("Warehouse"), "fieldname": "warehouse", "fieldtype": "Link", "options": "Warehouse", "width": 100},
{"label": _("Stock UOM"), "fieldname": "stock_uom", "fieldtype": "Link", "options": "UOM", "width": 90}, {"label": _("Stock UOM"), "fieldname": "stock_uom", "fieldtype": "Link", "options": "UOM", "width": 90},
{"label": _("Balance Qty"), "fieldname": "bal_qty", "fieldtype": "Float", "width": 100, "convertible": "qty"}, {"label": _("Balance Qty"), "fieldname": "bal_qty", "fieldtype": "Float", "width": 100, "convertible": "qty"},
{"label": _("Balance Value"), "fieldname": "bal_val", "fieldtype": "Currency", "width": 100}, {"label": _("Balance Value"), "fieldname": "bal_val", "fieldtype": "Currency", "width": 100, "options": "currency"},
{"label": _("Opening Qty"), "fieldname": "opening_qty", "fieldtype": "Float", "width": 100, "convertible": "qty"}, {"label": _("Opening Qty"), "fieldname": "opening_qty", "fieldtype": "Float", "width": 100, "convertible": "qty"},
{"label": _("Opening Value"), "fieldname": "opening_val", "fieldtype": "Float", "width": 110}, {"label": _("Opening Value"), "fieldname": "opening_val", "fieldtype": "Currency", "width": 110, "options": "currency"},
{"label": _("In Qty"), "fieldname": "in_qty", "fieldtype": "Float", "width": 80, "convertible": "qty"}, {"label": _("In Qty"), "fieldname": "in_qty", "fieldtype": "Float", "width": 80, "convertible": "qty"},
{"label": _("In Value"), "fieldname": "in_val", "fieldtype": "Float", "width": 80}, {"label": _("In Value"), "fieldname": "in_val", "fieldtype": "Float", "width": 80},
{"label": _("Out Qty"), "fieldname": "out_qty", "fieldtype": "Float", "width": 80, "convertible": "qty"}, {"label": _("Out Qty"), "fieldname": "out_qty", "fieldtype": "Float", "width": 80, "convertible": "qty"},
{"label": _("Out Value"), "fieldname": "out_val", "fieldtype": "Float", "width": 80}, {"label": _("Out Value"), "fieldname": "out_val", "fieldtype": "Float", "width": 80},
{"label": _("Valuation Rate"), "fieldname": "val_rate", "fieldtype": "Currency", "width": 90, "convertible": "rate"}, {"label": _("Valuation Rate"), "fieldname": "val_rate", "fieldtype": "Currency", "width": 90, "convertible": "rate", "options": "currency"},
{"label": _("Reorder Level"), "fieldname": "reorder_level", "fieldtype": "Float", "width": 80, "convertible": "qty"}, {"label": _("Reorder Level"), "fieldname": "reorder_level", "fieldtype": "Float", "width": 80, "convertible": "qty"},
{"label": _("Reorder Qty"), "fieldname": "reorder_qty", "fieldtype": "Float", "width": 80, "convertible": "qty"}, {"label": _("Reorder Qty"), "fieldname": "reorder_qty", "fieldtype": "Float", "width": 80, "convertible": "qty"},
{"label": _("Company"), "fieldname": "company", "fieldtype": "Link", "options": "Company", "width": 100} {"label": _("Company"), "fieldname": "company", "fieldtype": "Link", "options": "Company", "width": 100}

View File

@ -4,10 +4,10 @@
from __future__ import unicode_literals from __future__ import unicode_literals
import frappe import frappe
from frappe.utils import cint, flt
from erpnext.stock.utils import update_included_uom_in_report from erpnext.stock.utils import update_included_uom_in_report
from frappe import _ from frappe import _
def execute(filters=None): def execute(filters=None):
include_uom = filters.get("include_uom") include_uom = filters.get("include_uom")
columns = get_columns() columns = get_columns()
@ -15,6 +15,7 @@ def execute(filters=None):
sl_entries = get_stock_ledger_entries(filters, items) sl_entries = get_stock_ledger_entries(filters, items)
item_details = get_item_details(items, sl_entries, include_uom) item_details = get_item_details(items, sl_entries, include_uom)
opening_row = get_opening_balance(filters, columns) opening_row = get_opening_balance(filters, columns)
precision = cint(frappe.db.get_single_value("System Settings", "float_precision"))
data = [] data = []
conversion_factors = [] conversion_factors = []
@ -29,10 +30,10 @@ def execute(filters=None):
sle.update(item_detail) sle.update(item_detail)
if filters.get("batch_no"): if filters.get("batch_no"):
actual_qty += sle.actual_qty actual_qty += flt(sle.actual_qty, precision)
stock_value += sle.stock_value_difference stock_value += sle.stock_value_difference
if sle.voucher_type == 'Stock Reconciliation': if sle.voucher_type == 'Stock Reconciliation' and not sle.actual_qty:
actual_qty = sle.qty_after_transaction actual_qty = sle.qty_after_transaction
stock_value = sle.stock_value stock_value = sle.stock_value

View File

@ -8,11 +8,11 @@ frappe.listview_settings['Issue'] = {
var method = "erpnext.support.doctype.issue.issue.set_multiple_status"; var method = "erpnext.support.doctype.issue.issue.set_multiple_status";
listview.page.add_menu_item(__("Set as Open"), function() { listview.page.add_action_item(__("Set as Open"), function() {
listview.call_for_selected_items(method, {"status": "Open"}); listview.call_for_selected_items(method, {"status": "Open"});
}); });
listview.page.add_menu_item(__("Set as Closed"), function() { listview.page.add_action_item(__("Set as Closed"), function() {
listview.call_for_selected_items(method, {"status": "Closed"}); listview.call_for_selected_items(method, {"status": "Closed"});
}); });
}, },

View File

@ -6,7 +6,7 @@ from __future__ import unicode_literals
import frappe import frappe
from frappe.model.document import Document from frappe.model.document import Document
from frappe import _ from frappe import _
from frappe.utils import getdate, get_weekdays from frappe.utils import getdate, get_weekdays, get_link_to_form
class ServiceLevelAgreement(Document): class ServiceLevelAgreement(Document):
@ -21,8 +21,8 @@ class ServiceLevelAgreement(Document):
for priority in self.priorities: for priority in self.priorities:
# Check if response and resolution time is set for every priority # Check if response and resolution time is set for every priority
if not (priority.response_time or priority.resolution_time): if not priority.response_time or not priority.resolution_time:
frappe.throw(_("Set Response Time and Resolution for Priority {0} at index {1}.").format(priority.priority, priority.idx)) frappe.throw(_("Set Response Time and Resolution Time for Priority {0} in row {1}.").format(priority.priority, priority.idx))
priorities.append(priority.priority) priorities.append(priority.priority)
@ -33,7 +33,7 @@ class ServiceLevelAgreement(Document):
resolution = priority.resolution_time resolution = priority.resolution_time
if response > resolution: if response > resolution:
frappe.throw(_("Response Time for {0} at index {1} can't be greater than Resolution Time.").format(priority.priority, priority.idx)) frappe.throw(_("Response Time for {0} priority in row {1} can't be greater than Resolution Time.").format(priority.priority, priority.idx))
# Check if repeated priority # Check if repeated priority
if not len(set(priorities)) == len(priorities): if not len(set(priorities)) == len(priorities):
@ -73,8 +73,9 @@ class ServiceLevelAgreement(Document):
frappe.throw(_("Workday {0} has been repeated.").format(repeated_days)) frappe.throw(_("Workday {0} has been repeated.").format(repeated_days))
def validate_doc(self): def validate_doc(self):
if not frappe.db.get_single_value("Support Settings", "track_service_level_agreement"): if not frappe.db.get_single_value("Support Settings", "track_service_level_agreement") and self.enable:
frappe.throw(_("Service Level Agreement tracking is not enabled.")) frappe.throw(_("{0} is not enabled in {1}").format(frappe.bold("Track Service Level Agreement"),
get_link_to_form("Support Settings", "Support Settings")))
if self.default_service_level_agreement: if self.default_service_level_agreement:
if frappe.db.exists("Service Level Agreement", {"default_service_level_agreement": "1", "name": ["!=", self.name]}): if frappe.db.exists("Service Level Agreement", {"default_service_level_agreement": "1", "name": ["!=", self.name]}):