mirror of
https://github.com/frappe/erpnext.git
synced 2026-06-10 00:19:00 +00:00
Merge pull request #31729 from frappe/develop
chore: version-14 beta release
This commit is contained in:
8
.github/helper/install.sh
vendored
8
.github/helper/install.sh
vendored
@@ -2,13 +2,6 @@
|
||||
|
||||
set -e
|
||||
|
||||
# Check for merge conflicts before proceeding
|
||||
python -m compileall -f "${GITHUB_WORKSPACE}"
|
||||
if grep -lr --exclude-dir=node_modules "^<<<<<<< " "${GITHUB_WORKSPACE}"
|
||||
then echo "Found merge conflicts"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
cd ~ || exit
|
||||
|
||||
sudo apt update && sudo apt install redis-server libcups2-dev
|
||||
@@ -63,6 +56,7 @@ sed -i 's/schedule:/# schedule:/g' Procfile
|
||||
sed -i 's/socketio:/# socketio:/g' Procfile
|
||||
sed -i 's/redis_socketio:/# redis_socketio:/g' Procfile
|
||||
|
||||
bench get-app payments
|
||||
bench get-app erpnext "${GITHUB_WORKSPACE}"
|
||||
|
||||
if [ "$TYPE" == "server" ]; then bench setup requirements --dev; fi
|
||||
|
||||
12
.github/workflows/patch.yml
vendored
12
.github/workflows/patch.yml
vendored
@@ -34,6 +34,14 @@ jobs:
|
||||
- name: Clone
|
||||
uses: actions/checkout@v2
|
||||
|
||||
- name: Check for valid Python & Merge Conflicts
|
||||
run: |
|
||||
python -m compileall -f "${GITHUB_WORKSPACE}"
|
||||
if grep -lr --exclude-dir=node_modules "^<<<<<<< " "${GITHUB_WORKSPACE}"
|
||||
then echo "Found merge conflicts"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
- name: Setup Python
|
||||
uses: "gabrielfalcao/pyenv-action@v9"
|
||||
with:
|
||||
@@ -105,7 +113,6 @@ jobs:
|
||||
echo "Updating to v$version"
|
||||
branch_name="version-$version-hotfix"
|
||||
|
||||
|
||||
git -C "apps/frappe" fetch --depth 1 upstream $branch_name:$branch_name
|
||||
git -C "apps/erpnext" fetch --depth 1 upstream $branch_name:$branch_name
|
||||
|
||||
@@ -114,6 +121,7 @@ jobs:
|
||||
|
||||
rm -rf ~/frappe-bench/env
|
||||
bench setup env
|
||||
bench pip install -e ./apps/payments
|
||||
bench pip install -e ./apps/erpnext
|
||||
|
||||
bench --site test_site migrate
|
||||
@@ -127,6 +135,8 @@ jobs:
|
||||
pyenv global $(pyenv versions | grep '3.10')
|
||||
rm -rf ~/frappe-bench/env
|
||||
bench -v setup env
|
||||
bench pip install -e ./apps/payments
|
||||
bench pip install -e ./apps/erpnext
|
||||
|
||||
bench --site test_site migrate
|
||||
bench --site test_site install-app payments
|
||||
|
||||
30
.github/workflows/semantic-commits.yml
vendored
Normal file
30
.github/workflows/semantic-commits.yml
vendored
Normal file
@@ -0,0 +1,30 @@
|
||||
name: Semantic Commits
|
||||
|
||||
on:
|
||||
pull_request: {}
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
|
||||
concurrency:
|
||||
group: commitcheck-erpnext-${{ github.event.number }}
|
||||
cancel-in-progress: true
|
||||
|
||||
jobs:
|
||||
commitlint:
|
||||
name: Check Commit Titles
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
with:
|
||||
fetch-depth: 200
|
||||
|
||||
- uses: actions/setup-node@v3
|
||||
with:
|
||||
node-version: 14
|
||||
check-latest: true
|
||||
|
||||
- name: Check commit titles
|
||||
run: |
|
||||
npm install @commitlint/cli @commitlint/config-conventional
|
||||
npx commitlint --verbose --from ${{ github.event.pull_request.base.sha }} --to ${{ github.event.pull_request.head.sha }}
|
||||
8
.github/workflows/server-tests-mariadb.yml
vendored
8
.github/workflows/server-tests-mariadb.yml
vendored
@@ -61,6 +61,14 @@ jobs:
|
||||
with:
|
||||
python-version: '3.10'
|
||||
|
||||
- name: Check for valid Python & Merge Conflicts
|
||||
run: |
|
||||
python -m compileall -f "${GITHUB_WORKSPACE}"
|
||||
if grep -lr --exclude-dir=node_modules "^<<<<<<< " "${GITHUB_WORKSPACE}"
|
||||
then echo "Found merge conflicts"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
- name: Setup Node
|
||||
uses: actions/setup-node@v2
|
||||
with:
|
||||
|
||||
9
.github/workflows/server-tests-postgres.yml
vendored
9
.github/workflows/server-tests-postgres.yml
vendored
@@ -48,6 +48,14 @@ jobs:
|
||||
with:
|
||||
python-version: '3.10'
|
||||
|
||||
- name: Check for valid Python & Merge Conflicts
|
||||
run: |
|
||||
python -m compileall -f "${GITHUB_WORKSPACE}"
|
||||
if grep -lr --exclude-dir=node_modules "^<<<<<<< " "${GITHUB_WORKSPACE}"
|
||||
then echo "Found merge conflicts"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
- name: Setup Node
|
||||
uses: actions/setup-node@v2
|
||||
with:
|
||||
@@ -90,7 +98,6 @@ jobs:
|
||||
restore-keys: |
|
||||
${{ runner.os }}-yarn-
|
||||
|
||||
|
||||
- name: Install
|
||||
run: bash ${GITHUB_WORKSPACE}/.github/helper/install.sh
|
||||
env:
|
||||
|
||||
25
commitlint.config.js
Normal file
25
commitlint.config.js
Normal file
@@ -0,0 +1,25 @@
|
||||
module.exports = {
|
||||
parserPreset: 'conventional-changelog-conventionalcommits',
|
||||
rules: {
|
||||
'subject-empty': [2, 'never'],
|
||||
'type-case': [2, 'always', 'lower-case'],
|
||||
'type-empty': [2, 'never'],
|
||||
'type-enum': [
|
||||
2,
|
||||
'always',
|
||||
[
|
||||
'build',
|
||||
'chore',
|
||||
'ci',
|
||||
'docs',
|
||||
'feat',
|
||||
'fix',
|
||||
'perf',
|
||||
'refactor',
|
||||
'revert',
|
||||
'style',
|
||||
'test',
|
||||
],
|
||||
],
|
||||
},
|
||||
};
|
||||
@@ -49,15 +49,9 @@ class AccountingPeriod(Document):
|
||||
@frappe.whitelist()
|
||||
def get_doctypes_for_closing(self):
|
||||
docs_for_closing = []
|
||||
doctypes = [
|
||||
"Sales Invoice",
|
||||
"Purchase Invoice",
|
||||
"Journal Entry",
|
||||
"Payroll Entry",
|
||||
"Bank Clearance",
|
||||
"Asset",
|
||||
"Stock Entry",
|
||||
]
|
||||
# get period closing doctypes from all the apps
|
||||
doctypes = frappe.get_hooks("period_closing_doctypes")
|
||||
|
||||
closed_doctypes = [{"document_type": doctype, "closed": 1} for doctype in doctypes]
|
||||
for closed_doctype in closed_doctypes:
|
||||
docs_for_closing.append(closed_doctype)
|
||||
|
||||
@@ -18,6 +18,7 @@
|
||||
"automatically_fetch_payment_terms",
|
||||
"column_break_17",
|
||||
"enable_common_party_accounting",
|
||||
"allow_multi_currency_invoices_against_single_party_account",
|
||||
"report_setting_section",
|
||||
"use_custom_cash_flow",
|
||||
"deferred_accounting_settings_section",
|
||||
@@ -339,6 +340,13 @@
|
||||
"fieldname": "report_setting_section",
|
||||
"fieldtype": "Section Break",
|
||||
"label": "Report Setting"
|
||||
},
|
||||
{
|
||||
"default": "0",
|
||||
"description": "Enabling this will allow creation of multi-currency invoices against single party account in company currency",
|
||||
"fieldname": "allow_multi_currency_invoices_against_single_party_account",
|
||||
"fieldtype": "Check",
|
||||
"label": "Allow multi-currency invoices against single party account "
|
||||
}
|
||||
],
|
||||
"icon": "icon-cog",
|
||||
@@ -346,7 +354,7 @@
|
||||
"index_web_pages_for_search": 1,
|
||||
"issingle": 1,
|
||||
"links": [],
|
||||
"modified": "2022-04-08 14:45:06.796418",
|
||||
"modified": "2022-07-11 13:37:50.605141",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Accounts",
|
||||
"name": "Accounts Settings",
|
||||
|
||||
@@ -104,7 +104,7 @@ class BankClearance(Document):
|
||||
|
||||
loan_repayment = frappe.qb.DocType("Loan Repayment")
|
||||
|
||||
loan_repayments = (
|
||||
query = (
|
||||
frappe.qb.from_(loan_repayment)
|
||||
.select(
|
||||
ConstantColumn("Loan Repayment").as_("payment_document"),
|
||||
@@ -118,13 +118,17 @@ class BankClearance(Document):
|
||||
)
|
||||
.where(loan_repayment.docstatus == 1)
|
||||
.where(loan_repayment.clearance_date.isnull())
|
||||
.where(loan_repayment.repay_from_salary == 0)
|
||||
.where(loan_repayment.posting_date >= self.from_date)
|
||||
.where(loan_repayment.posting_date <= self.to_date)
|
||||
.where(loan_repayment.payment_account.isin([self.bank_account, self.account]))
|
||||
.orderby(loan_repayment.posting_date)
|
||||
.orderby(loan_repayment.name, frappe.qb.desc)
|
||||
).run(as_dict=1)
|
||||
)
|
||||
|
||||
if frappe.db.has_column("Loan Repayment", "repay_from_salary"):
|
||||
query = query.where((loan_repayment.repay_from_salary == 0))
|
||||
|
||||
query = query.orderby(loan_repayment.posting_date).orderby(loan_repayment.name, frappe.qb.desc)
|
||||
|
||||
loan_repayments = query.run(as_dict=True)
|
||||
|
||||
pos_sales_invoices, pos_purchase_invoices = [], []
|
||||
if self.include_pos_transactions:
|
||||
|
||||
@@ -10,7 +10,6 @@ from frappe.model.document import Document
|
||||
from frappe.query_builder.custom import ConstantColumn
|
||||
from frappe.utils import flt
|
||||
|
||||
from erpnext import get_company_currency
|
||||
from erpnext.accounts.doctype.bank_transaction.bank_transaction import get_paid_amount
|
||||
from erpnext.accounts.report.bank_reconciliation_statement.bank_reconciliation_statement import (
|
||||
get_amounts_not_reflected_in_system,
|
||||
@@ -368,6 +367,27 @@ def get_queries(bank_account, company, transaction, document_types):
|
||||
account_from_to = "paid_to" if transaction.deposit > 0 else "paid_from"
|
||||
queries = []
|
||||
|
||||
# get matching queries from all the apps
|
||||
for method_name in frappe.get_hooks("get_matching_queries"):
|
||||
queries.extend(
|
||||
frappe.get_attr(method_name)(
|
||||
bank_account,
|
||||
company,
|
||||
transaction,
|
||||
document_types,
|
||||
amount_condition,
|
||||
account_from_to,
|
||||
)
|
||||
or []
|
||||
)
|
||||
|
||||
return queries
|
||||
|
||||
|
||||
def get_matching_queries(
|
||||
bank_account, company, transaction, document_types, amount_condition, account_from_to
|
||||
):
|
||||
queries = []
|
||||
if "payment_entry" in document_types:
|
||||
pe_amount_matching = get_pe_matching_query(amount_condition, account_from_to, transaction)
|
||||
queries.extend([pe_amount_matching])
|
||||
@@ -385,10 +405,6 @@ def get_queries(bank_account, company, transaction, document_types):
|
||||
pi_amount_matching = get_pi_matching_query(amount_condition)
|
||||
queries.extend([pi_amount_matching])
|
||||
|
||||
if "expense_claim" in document_types:
|
||||
ec_amount_matching = get_ec_matching_query(bank_account, company, amount_condition)
|
||||
queries.extend([ec_amount_matching])
|
||||
|
||||
return queries
|
||||
|
||||
|
||||
@@ -467,11 +483,13 @@ def get_lr_matching_query(bank_account, amount_condition, filters):
|
||||
loan_repayment.posting_date,
|
||||
)
|
||||
.where(loan_repayment.docstatus == 1)
|
||||
.where(loan_repayment.repay_from_salary == 0)
|
||||
.where(loan_repayment.clearance_date.isnull())
|
||||
.where(loan_repayment.payment_account == bank_account)
|
||||
)
|
||||
|
||||
if frappe.db.has_column("Loan Repayment", "repay_from_salary"):
|
||||
query = query.where((loan_repayment.repay_from_salary == 0))
|
||||
|
||||
if amount_condition:
|
||||
query.where(loan_repayment.amount_paid == filters.get("amount"))
|
||||
else:
|
||||
@@ -602,37 +620,3 @@ def get_pi_matching_query(amount_condition):
|
||||
AND ifnull(clearance_date, '') = ""
|
||||
AND cash_bank_account = %(bank_account)s
|
||||
"""
|
||||
|
||||
|
||||
def get_ec_matching_query(bank_account, company, amount_condition):
|
||||
# get matching Expense Claim query
|
||||
mode_of_payments = [
|
||||
x["parent"]
|
||||
for x in frappe.db.get_all(
|
||||
"Mode of Payment Account", filters={"default_account": bank_account}, fields=["parent"]
|
||||
)
|
||||
]
|
||||
mode_of_payments = "('" + "', '".join(mode_of_payments) + "' )"
|
||||
company_currency = get_company_currency(company)
|
||||
return f"""
|
||||
SELECT
|
||||
( CASE WHEN employee = %(party)s THEN 1 ELSE 0 END
|
||||
+ 1 ) AS rank,
|
||||
'Expense Claim' as doctype,
|
||||
name,
|
||||
total_sanctioned_amount as paid_amount,
|
||||
'' as reference_no,
|
||||
'' as reference_date,
|
||||
employee as party,
|
||||
'Employee' as party_type,
|
||||
posting_date,
|
||||
'{company_currency}' as currency
|
||||
FROM
|
||||
`tabExpense Claim`
|
||||
WHERE
|
||||
total_sanctioned_amount {amount_condition} %(amount)s
|
||||
AND docstatus = 1
|
||||
AND is_paid = 1
|
||||
AND ifnull(clearance_date, '') = ""
|
||||
AND mode_of_payment in {mode_of_payments}
|
||||
"""
|
||||
|
||||
@@ -3,28 +3,21 @@
|
||||
|
||||
frappe.ui.form.on("Bank Transaction", {
|
||||
onload(frm) {
|
||||
frm.set_query("payment_document", "payment_entries", function () {
|
||||
frm.set_query("payment_document", "payment_entries", function() {
|
||||
const payment_doctypes = frm.events.get_payment_doctypes(frm);
|
||||
return {
|
||||
filters: {
|
||||
name: [
|
||||
"in",
|
||||
[
|
||||
"Payment Entry",
|
||||
"Journal Entry",
|
||||
"Sales Invoice",
|
||||
"Purchase Invoice",
|
||||
"Expense Claim",
|
||||
],
|
||||
],
|
||||
name: ["in", payment_doctypes],
|
||||
},
|
||||
};
|
||||
});
|
||||
},
|
||||
bank_account: function (frm) {
|
||||
|
||||
bank_account: function(frm) {
|
||||
set_bank_statement_filter(frm);
|
||||
},
|
||||
|
||||
setup: function (frm) {
|
||||
setup: function(frm) {
|
||||
frm.set_query("party_type", function () {
|
||||
return {
|
||||
filters: {
|
||||
@@ -33,6 +26,16 @@ frappe.ui.form.on("Bank Transaction", {
|
||||
};
|
||||
});
|
||||
},
|
||||
|
||||
get_payment_doctypes: function() {
|
||||
// get payment doctypes from all the apps
|
||||
return [
|
||||
"Payment Entry",
|
||||
"Journal Entry",
|
||||
"Sales Invoice",
|
||||
"Purchase Invoice",
|
||||
];
|
||||
}
|
||||
});
|
||||
|
||||
frappe.ui.form.on("Bank Transaction Payments", {
|
||||
|
||||
@@ -58,18 +58,10 @@ class BankTransaction(StatusUpdater):
|
||||
|
||||
def clear_linked_payment_entries(self, for_cancel=False):
|
||||
for payment_entry in self.payment_entries:
|
||||
if payment_entry.payment_document in [
|
||||
"Payment Entry",
|
||||
"Journal Entry",
|
||||
"Purchase Invoice",
|
||||
"Expense Claim",
|
||||
"Loan Repayment",
|
||||
"Loan Disbursement",
|
||||
]:
|
||||
self.clear_simple_entry(payment_entry, for_cancel=for_cancel)
|
||||
|
||||
elif payment_entry.payment_document == "Sales Invoice":
|
||||
if payment_entry.payment_document == "Sales Invoice":
|
||||
self.clear_sales_invoice(payment_entry, for_cancel=for_cancel)
|
||||
elif payment_entry.payment_document in get_doctypes_for_bank_reconciliation():
|
||||
self.clear_simple_entry(payment_entry, for_cancel=for_cancel)
|
||||
|
||||
def clear_simple_entry(self, payment_entry, for_cancel=False):
|
||||
if payment_entry.payment_document == "Payment Entry":
|
||||
@@ -95,6 +87,12 @@ class BankTransaction(StatusUpdater):
|
||||
)
|
||||
|
||||
|
||||
@frappe.whitelist()
|
||||
def get_doctypes_for_bank_reconciliation():
|
||||
"""Get Bank Reconciliation doctypes from all the apps"""
|
||||
return frappe.get_hooks("bank_reconciliation_doctypes")
|
||||
|
||||
|
||||
def get_reconciled_bank_transactions(payment_entry):
|
||||
reconciled_bank_transactions = frappe.get_all(
|
||||
"Bank Transaction Payments",
|
||||
|
||||
@@ -5,6 +5,7 @@ import json
|
||||
import unittest
|
||||
|
||||
import frappe
|
||||
from frappe.tests.utils import FrappeTestCase
|
||||
|
||||
from erpnext.accounts.doctype.bank_reconciliation_tool.bank_reconciliation_tool import (
|
||||
get_linked_payments,
|
||||
@@ -18,28 +19,21 @@ from erpnext.accounts.doctype.sales_invoice.test_sales_invoice import create_sal
|
||||
test_dependencies = ["Item", "Cost Center"]
|
||||
|
||||
|
||||
class TestBankTransaction(unittest.TestCase):
|
||||
@classmethod
|
||||
def setUpClass(cls):
|
||||
class TestBankTransaction(FrappeTestCase):
|
||||
def setUp(self):
|
||||
for dt in [
|
||||
"Loan Repayment",
|
||||
"Bank Transaction",
|
||||
"Payment Entry",
|
||||
"Payment Entry Reference",
|
||||
"POS Profile",
|
||||
]:
|
||||
frappe.db.delete(dt)
|
||||
|
||||
make_pos_profile()
|
||||
add_transactions()
|
||||
add_vouchers()
|
||||
|
||||
@classmethod
|
||||
def tearDownClass(cls):
|
||||
for bt in frappe.get_all("Bank Transaction"):
|
||||
doc = frappe.get_doc("Bank Transaction", bt.name)
|
||||
if doc.docstatus == 1:
|
||||
doc.cancel()
|
||||
doc.delete()
|
||||
|
||||
# Delete directly in DB to avoid validation errors for countries not allowing deletion
|
||||
frappe.db.sql("""delete from `tabPayment Entry Reference`""")
|
||||
frappe.db.sql("""delete from `tabPayment Entry`""")
|
||||
|
||||
# Delete POS Profile
|
||||
frappe.db.sql("delete from `tabPOS Profile`")
|
||||
|
||||
# This test checks if ERPNext is able to provide a linked payment for a bank transaction based on the amount of the bank transaction.
|
||||
def test_linked_payments(self):
|
||||
bank_transaction = frappe.get_doc(
|
||||
@@ -155,6 +149,35 @@ class TestBankTransaction(unittest.TestCase):
|
||||
is not None
|
||||
)
|
||||
|
||||
def test_matching_loan_repayment(self):
|
||||
from erpnext.loan_management.doctype.loan.test_loan import create_loan_accounts
|
||||
|
||||
create_loan_accounts()
|
||||
bank_account = frappe.get_doc(
|
||||
{
|
||||
"doctype": "Bank Account",
|
||||
"account_name": "Payment Account",
|
||||
"bank": "Citi Bank",
|
||||
"account": "Payment Account - _TC",
|
||||
}
|
||||
).insert(ignore_if_duplicate=True)
|
||||
|
||||
bank_transaction = frappe.get_doc(
|
||||
{
|
||||
"doctype": "Bank Transaction",
|
||||
"description": "Loan Repayment - OPSKATTUZWXXX AT776000000098709837 Herr G",
|
||||
"date": "2018-10-27",
|
||||
"deposit": 500,
|
||||
"currency": "INR",
|
||||
"bank_account": bank_account.name,
|
||||
}
|
||||
).submit()
|
||||
|
||||
repayment_entry = create_loan_and_repayment()
|
||||
|
||||
linked_payments = get_linked_payments(bank_transaction.name, ["loan_repayment", "exact_match"])
|
||||
self.assertEqual(linked_payments[0][2], repayment_entry.name)
|
||||
|
||||
|
||||
def create_bank_account(bank_name="Citi Bank", account_name="_Test Bank - _TC"):
|
||||
try:
|
||||
@@ -364,3 +387,59 @@ def add_vouchers():
|
||||
)
|
||||
si.insert()
|
||||
si.submit()
|
||||
|
||||
|
||||
def create_loan_and_repayment():
|
||||
from erpnext.loan_management.doctype.loan.test_loan import (
|
||||
create_loan,
|
||||
create_loan_type,
|
||||
create_repayment_entry,
|
||||
make_loan_disbursement_entry,
|
||||
)
|
||||
from erpnext.loan_management.doctype.process_loan_interest_accrual.process_loan_interest_accrual import (
|
||||
process_loan_interest_accrual_for_term_loans,
|
||||
)
|
||||
from erpnext.setup.doctype.employee.test_employee import make_employee
|
||||
|
||||
create_loan_type(
|
||||
"Personal Loan",
|
||||
500000,
|
||||
8.4,
|
||||
is_term_loan=1,
|
||||
mode_of_payment="Cash",
|
||||
disbursement_account="Disbursement Account - _TC",
|
||||
payment_account="Payment Account - _TC",
|
||||
loan_account="Loan Account - _TC",
|
||||
interest_income_account="Interest Income Account - _TC",
|
||||
penalty_income_account="Penalty Income Account - _TC",
|
||||
)
|
||||
|
||||
applicant = make_employee("test_bank_reco@loan.com", company="_Test Company")
|
||||
loan = create_loan(applicant, "Personal Loan", 5000, "Repay Over Number of Periods", 20)
|
||||
loan = frappe.get_doc(
|
||||
{
|
||||
"doctype": "Loan",
|
||||
"applicant_type": "Employee",
|
||||
"company": "_Test Company",
|
||||
"applicant": applicant,
|
||||
"loan_type": "Personal Loan",
|
||||
"loan_amount": 5000,
|
||||
"repayment_method": "Repay Fixed Amount per Period",
|
||||
"monthly_repayment_amount": 500,
|
||||
"repayment_start_date": "2018-09-27",
|
||||
"is_term_loan": 1,
|
||||
"posting_date": "2018-09-27",
|
||||
}
|
||||
).insert()
|
||||
|
||||
make_loan_disbursement_entry(loan.name, loan.loan_amount, disbursement_date="2018-09-27")
|
||||
process_loan_interest_accrual_for_term_loans(posting_date="2018-10-27")
|
||||
|
||||
repayment_entry = create_repayment_entry(
|
||||
loan.name,
|
||||
applicant,
|
||||
"2018-10-27",
|
||||
500,
|
||||
)
|
||||
repayment_entry.submit()
|
||||
return repayment_entry
|
||||
|
||||
@@ -42,7 +42,7 @@ class GLEntry(Document):
|
||||
self.validate_and_set_fiscal_year()
|
||||
self.pl_must_have_cost_center()
|
||||
|
||||
if not self.flags.from_repost:
|
||||
if not self.flags.from_repost and self.voucher_type != "Period Closing Voucher":
|
||||
self.check_mandatory()
|
||||
self.validate_cost_center()
|
||||
self.check_pl_account()
|
||||
@@ -51,7 +51,7 @@ class GLEntry(Document):
|
||||
|
||||
def on_update(self):
|
||||
adv_adj = self.flags.adv_adj
|
||||
if not self.flags.from_repost:
|
||||
if not self.flags.from_repost and self.voucher_type != "Period Closing Voucher":
|
||||
self.validate_account_details(adv_adj)
|
||||
self.validate_dimensions_for_pl_and_bs()
|
||||
self.validate_allowed_dimensions()
|
||||
|
||||
@@ -224,25 +224,6 @@ erpnext.accounts.JournalEntry = class JournalEntry extends frappe.ui.form.Contro
|
||||
me.frm.set_query("reference_name", "accounts", function(doc, cdt, cdn) {
|
||||
var jvd = frappe.get_doc(cdt, cdn);
|
||||
|
||||
// expense claim
|
||||
if(jvd.reference_type==="Expense Claim") {
|
||||
return {
|
||||
filters: {
|
||||
'total_sanctioned_amount': ['>', 0],
|
||||
'status': ['!=', 'Paid'],
|
||||
'docstatus': 1
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
if(jvd.reference_type==="Employee Advance") {
|
||||
return {
|
||||
filters: {
|
||||
'docstatus': 1
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
// journal entry
|
||||
if(jvd.reference_type==="Journal Entry") {
|
||||
frappe.model.validate_missing(jvd, "account");
|
||||
@@ -255,13 +236,6 @@ erpnext.accounts.JournalEntry = class JournalEntry extends frappe.ui.form.Contro
|
||||
};
|
||||
}
|
||||
|
||||
// payroll entry
|
||||
if(jvd.reference_type==="Payroll Entry") {
|
||||
return {
|
||||
query: "erpnext.payroll.doctype.payroll_entry.payroll_entry.get_payroll_entries_for_jv",
|
||||
};
|
||||
}
|
||||
|
||||
var out = {
|
||||
filters: [
|
||||
[jvd.reference_type, "docstatus", "=", 1]
|
||||
|
||||
@@ -24,7 +24,6 @@ from erpnext.accounts.utils import (
|
||||
get_stock_and_account_balance,
|
||||
)
|
||||
from erpnext.controllers.accounts_controller import AccountsController
|
||||
from erpnext.hr.doctype.expense_claim.expense_claim import update_reimbursed_amount
|
||||
|
||||
|
||||
class StockAccountInvalidTransaction(frappe.ValidationError):
|
||||
@@ -66,7 +65,6 @@ class JournalEntry(AccountsController):
|
||||
self.set_against_account()
|
||||
self.create_remarks()
|
||||
self.set_print_format_fields()
|
||||
self.validate_expense_claim()
|
||||
self.validate_credit_debit_note()
|
||||
self.validate_empty_accounts_table()
|
||||
self.set_account_and_party_balance()
|
||||
@@ -83,27 +81,21 @@ class JournalEntry(AccountsController):
|
||||
self.check_credit_limit()
|
||||
self.make_gl_entries()
|
||||
self.update_advance_paid()
|
||||
self.update_expense_claim()
|
||||
self.update_inter_company_jv()
|
||||
self.update_invoice_discounting()
|
||||
self.update_status_for_full_and_final_statement()
|
||||
|
||||
def on_cancel(self):
|
||||
from erpnext.accounts.utils import unlink_ref_doc_from_payment_entries
|
||||
from erpnext.payroll.doctype.salary_slip.salary_slip import unlink_ref_doc_from_salary_slip
|
||||
|
||||
unlink_ref_doc_from_payment_entries(self)
|
||||
unlink_ref_doc_from_salary_slip(self.name)
|
||||
self.ignore_linked_doctypes = ("GL Entry", "Stock Ledger Entry", "Payment Ledger Entry")
|
||||
self.make_gl_entries(1)
|
||||
self.update_advance_paid()
|
||||
self.update_expense_claim()
|
||||
self.unlink_advance_entry_reference()
|
||||
self.unlink_asset_reference()
|
||||
self.unlink_inter_company_jv()
|
||||
self.unlink_asset_adjustment_entry()
|
||||
self.update_invoice_discounting()
|
||||
self.update_status_for_full_and_final_statement()
|
||||
|
||||
def get_title(self):
|
||||
return self.pay_to_recd_from or self.accounts[0].account
|
||||
@@ -112,21 +104,13 @@ class JournalEntry(AccountsController):
|
||||
advance_paid = frappe._dict()
|
||||
for d in self.get("accounts"):
|
||||
if d.is_advance:
|
||||
if d.reference_type in ("Sales Order", "Purchase Order", "Employee Advance"):
|
||||
if d.reference_type in frappe.get_hooks("advance_payment_doctypes"):
|
||||
advance_paid.setdefault(d.reference_type, []).append(d.reference_name)
|
||||
|
||||
for voucher_type, order_list in advance_paid.items():
|
||||
for voucher_no in list(set(order_list)):
|
||||
frappe.get_doc(voucher_type, voucher_no).set_total_advance_paid()
|
||||
|
||||
def update_status_for_full_and_final_statement(self):
|
||||
for entry in self.accounts:
|
||||
if entry.reference_type == "Full and Final Statement":
|
||||
if self.docstatus == 1:
|
||||
frappe.db.set_value("Full and Final Statement", entry.reference_name, "status", "Paid")
|
||||
elif self.docstatus == 2:
|
||||
frappe.db.set_value("Full and Final Statement", entry.reference_name, "status", "Unpaid")
|
||||
|
||||
def validate_inter_company_accounts(self):
|
||||
if (
|
||||
self.voucher_type == "Inter Company Journal Entry"
|
||||
@@ -935,29 +919,6 @@ class JournalEntry(AccountsController):
|
||||
as_dict=True,
|
||||
)
|
||||
|
||||
def update_expense_claim(self):
|
||||
for d in self.accounts:
|
||||
if d.reference_type == "Expense Claim" and d.reference_name:
|
||||
doc = frappe.get_doc("Expense Claim", d.reference_name)
|
||||
if self.docstatus == 2:
|
||||
update_reimbursed_amount(doc, -1 * d.debit)
|
||||
else:
|
||||
update_reimbursed_amount(doc, d.debit)
|
||||
|
||||
def validate_expense_claim(self):
|
||||
for d in self.accounts:
|
||||
if d.reference_type == "Expense Claim":
|
||||
sanctioned_amount, reimbursed_amount = frappe.db.get_value(
|
||||
"Expense Claim", d.reference_name, ("total_sanctioned_amount", "total_amount_reimbursed")
|
||||
)
|
||||
pending_amount = flt(sanctioned_amount) - flt(reimbursed_amount)
|
||||
if d.debit > pending_amount:
|
||||
frappe.throw(
|
||||
_(
|
||||
"Row No {0}: Amount cannot be greater than Pending Amount against Expense Claim {1}. Pending Amount is {2}"
|
||||
).format(d.idx, d.reference_name, pending_amount)
|
||||
)
|
||||
|
||||
def validate_credit_debit_note(self):
|
||||
if self.stock_entry:
|
||||
if frappe.db.get_value("Stock Entry", self.stock_entry, "docstatus") != 1:
|
||||
|
||||
@@ -110,8 +110,6 @@ frappe.ui.form.on('Payment Entry', {
|
||||
var doctypes = ["Sales Order", "Sales Invoice", "Journal Entry", "Dunning"];
|
||||
} else if (frm.doc.party_type == "Supplier") {
|
||||
var doctypes = ["Purchase Order", "Purchase Invoice", "Journal Entry"];
|
||||
} else if (frm.doc.party_type == "Employee") {
|
||||
var doctypes = ["Expense Claim", "Journal Entry"];
|
||||
} else {
|
||||
var doctypes = ["Journal Entry"];
|
||||
}
|
||||
@@ -140,17 +138,12 @@ frappe.ui.form.on('Payment Entry', {
|
||||
const child = locals[cdt][cdn];
|
||||
const filters = {"docstatus": 1, "company": doc.company};
|
||||
const party_type_doctypes = ['Sales Invoice', 'Sales Order', 'Purchase Invoice',
|
||||
'Purchase Order', 'Expense Claim', 'Fees', 'Dunning'];
|
||||
'Purchase Order', 'Dunning'];
|
||||
|
||||
if (in_list(party_type_doctypes, child.reference_doctype)) {
|
||||
filters[doc.party_type.toLowerCase()] = doc.party;
|
||||
}
|
||||
|
||||
if(child.reference_doctype == "Expense Claim") {
|
||||
filters["docstatus"] = 1;
|
||||
filters["is_paid"] = 0;
|
||||
}
|
||||
|
||||
return {
|
||||
filters: filters
|
||||
};
|
||||
@@ -730,7 +723,7 @@ frappe.ui.form.on('Payment Entry', {
|
||||
c.payment_term = d.payment_term;
|
||||
c.allocated_amount = d.allocated_amount;
|
||||
|
||||
if(!in_list(["Sales Order", "Purchase Order", "Expense Claim", "Fees"], d.voucher_type)) {
|
||||
if(!in_list(frm.events.get_order_doctypes(frm), d.voucher_type)) {
|
||||
if(flt(d.outstanding_amount) > 0)
|
||||
total_positive_outstanding += flt(d.outstanding_amount);
|
||||
else
|
||||
@@ -745,7 +738,7 @@ frappe.ui.form.on('Payment Entry', {
|
||||
} else {
|
||||
c.exchange_rate = 1;
|
||||
}
|
||||
if (in_list(['Sales Invoice', 'Purchase Invoice', "Expense Claim", "Fees"], d.reference_doctype)){
|
||||
if (in_list(frm.events.get_invoice_doctypes(frm), d.reference_doctype)){
|
||||
c.due_date = d.due_date;
|
||||
}
|
||||
});
|
||||
@@ -776,6 +769,14 @@ frappe.ui.form.on('Payment Entry', {
|
||||
});
|
||||
},
|
||||
|
||||
get_order_doctypes: function(frm) {
|
||||
return ["Sales Order", "Purchase Order"];
|
||||
},
|
||||
|
||||
get_invoice_doctypes: function(frm) {
|
||||
return ["Sales Invoice", "Purchase Invoice"];
|
||||
},
|
||||
|
||||
allocate_party_amount_against_ref_docs: function(frm, paid_amount, paid_amount_change) {
|
||||
var total_positive_outstanding_including_order = 0;
|
||||
var total_negative_outstanding = 0;
|
||||
@@ -946,14 +947,6 @@ frappe.ui.form.on('Payment Entry', {
|
||||
frappe.msgprint(__("Row #{0}: Reference Document Type must be one of Purchase Order, Purchase Invoice or Journal Entry", [row.idx]));
|
||||
return false;
|
||||
}
|
||||
|
||||
if(frm.doc.party_type=="Employee" &&
|
||||
!in_list(["Expense Claim", "Journal Entry"], row.reference_doctype)
|
||||
) {
|
||||
frappe.model.set_value(row.doctype, row.name, "against_voucher_type", null);
|
||||
frappe.msgprint(__("Row #{0}: Reference Document Type must be one of Expense Claim or Journal Entry", [row.idx]));
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (row) {
|
||||
|
||||
@@ -29,7 +29,6 @@ from erpnext.controllers.accounts_controller import (
|
||||
get_supplier_block_status,
|
||||
validate_taxes_and_charges,
|
||||
)
|
||||
from erpnext.hr.doctype.expense_claim.expense_claim import update_reimbursed_amount
|
||||
from erpnext.setup.utils import get_exchange_rate
|
||||
|
||||
|
||||
@@ -88,7 +87,6 @@ class PaymentEntry(AccountsController):
|
||||
if self.difference_amount:
|
||||
frappe.throw(_("Difference Amount must be zero"))
|
||||
self.make_gl_entries()
|
||||
self.update_expense_claim()
|
||||
self.update_outstanding_amounts()
|
||||
self.update_advance_paid()
|
||||
self.update_payment_schedule()
|
||||
@@ -97,7 +95,6 @@ class PaymentEntry(AccountsController):
|
||||
def on_cancel(self):
|
||||
self.ignore_linked_doctypes = ("GL Entry", "Stock Ledger Entry", "Payment Ledger Entry")
|
||||
self.make_gl_entries(cancel=1)
|
||||
self.update_expense_claim()
|
||||
self.update_outstanding_amounts()
|
||||
self.update_advance_paid()
|
||||
self.delink_advance_entry_references()
|
||||
@@ -296,14 +293,7 @@ class PaymentEntry(AccountsController):
|
||||
frappe.throw(_("{0} is mandatory").format(self.meta.get_label(field)))
|
||||
|
||||
def validate_reference_documents(self):
|
||||
if self.party_type == "Customer":
|
||||
valid_reference_doctypes = ("Sales Order", "Sales Invoice", "Journal Entry", "Dunning")
|
||||
elif self.party_type == "Supplier":
|
||||
valid_reference_doctypes = ("Purchase Order", "Purchase Invoice", "Journal Entry")
|
||||
elif self.party_type == "Employee":
|
||||
valid_reference_doctypes = ("Expense Claim", "Journal Entry", "Employee Advance", "Gratuity")
|
||||
elif self.party_type == "Shareholder":
|
||||
valid_reference_doctypes = "Journal Entry"
|
||||
valid_reference_doctypes = self.get_valid_reference_doctypes()
|
||||
|
||||
for d in self.get("references"):
|
||||
if not d.allocated_amount:
|
||||
@@ -329,7 +319,7 @@ class PaymentEntry(AccountsController):
|
||||
else:
|
||||
self.validate_journal_entry()
|
||||
|
||||
if d.reference_doctype in ("Sales Invoice", "Purchase Invoice", "Expense Claim", "Fees"):
|
||||
if d.reference_doctype in frappe.get_hooks("invoice_doctypes"):
|
||||
if self.party_type == "Customer":
|
||||
ref_party_account = (
|
||||
get_party_account_based_on_invoice_discounting(d.reference_name) or ref_doc.debit_to
|
||||
@@ -355,6 +345,16 @@ class PaymentEntry(AccountsController):
|
||||
if ref_doc.docstatus != 1:
|
||||
frappe.throw(_("{0} {1} must be submitted").format(d.reference_doctype, d.reference_name))
|
||||
|
||||
def get_valid_reference_doctypes(self):
|
||||
if self.party_type == "Customer":
|
||||
return ("Sales Order", "Sales Invoice", "Journal Entry", "Dunning")
|
||||
elif self.party_type == "Supplier":
|
||||
return ("Purchase Order", "Purchase Invoice", "Journal Entry")
|
||||
elif self.party_type == "Shareholder":
|
||||
return ("Journal Entry",)
|
||||
elif self.party_type == "Employee":
|
||||
return ("Journal Entry",)
|
||||
|
||||
def validate_paid_invoices(self):
|
||||
no_oustanding_refs = {}
|
||||
|
||||
@@ -980,24 +980,9 @@ class PaymentEntry(AccountsController):
|
||||
def update_advance_paid(self):
|
||||
if self.payment_type in ("Receive", "Pay") and self.party:
|
||||
for d in self.get("references"):
|
||||
if d.allocated_amount and d.reference_doctype in (
|
||||
"Sales Order",
|
||||
"Purchase Order",
|
||||
"Employee Advance",
|
||||
"Gratuity",
|
||||
):
|
||||
if d.allocated_amount and d.reference_doctype in frappe.get_hooks("advance_payment_doctypes"):
|
||||
frappe.get_doc(d.reference_doctype, d.reference_name).set_total_advance_paid()
|
||||
|
||||
def update_expense_claim(self):
|
||||
if self.payment_type in ("Pay") and self.party:
|
||||
for d in self.get("references"):
|
||||
if d.reference_doctype == "Expense Claim" and d.reference_name:
|
||||
doc = frappe.get_doc("Expense Claim", d.reference_name)
|
||||
if self.docstatus == 2:
|
||||
update_reimbursed_amount(doc, -1 * d.allocated_amount)
|
||||
else:
|
||||
update_reimbursed_amount(doc, d.allocated_amount)
|
||||
|
||||
def on_recurring(self, reference_doc, auto_repeat_doc):
|
||||
self.reference_no = reference_doc.name
|
||||
self.reference_date = nowdate()
|
||||
@@ -1191,7 +1176,6 @@ def validate_inclusive_tax(tax, doc):
|
||||
|
||||
@frappe.whitelist()
|
||||
def get_outstanding_reference_documents(args):
|
||||
|
||||
if isinstance(args, str):
|
||||
args = json.loads(args)
|
||||
|
||||
@@ -1260,7 +1244,7 @@ def get_outstanding_reference_documents(args):
|
||||
for d in outstanding_invoices:
|
||||
d["exchange_rate"] = 1
|
||||
if party_account_currency != company_currency:
|
||||
if d.voucher_type in ("Sales Invoice", "Purchase Invoice", "Expense Claim"):
|
||||
if d.voucher_type in frappe.get_hooks("invoice_doctypes"):
|
||||
d["exchange_rate"] = frappe.db.get_value(d.voucher_type, d.voucher_no, "conversion_rate")
|
||||
elif d.voucher_type == "Journal Entry":
|
||||
d["exchange_rate"] = get_exchange_rate(
|
||||
@@ -1587,20 +1571,17 @@ def get_outstanding_on_journal_entry(name):
|
||||
|
||||
@frappe.whitelist()
|
||||
def get_reference_details(reference_doctype, reference_name, party_account_currency):
|
||||
total_amount = outstanding_amount = exchange_rate = bill_no = None
|
||||
total_amount = outstanding_amount = exchange_rate = None
|
||||
|
||||
ref_doc = frappe.get_doc(reference_doctype, reference_name)
|
||||
company_currency = ref_doc.get("company_currency") or erpnext.get_company_currency(
|
||||
ref_doc.company
|
||||
)
|
||||
|
||||
if reference_doctype == "Fees":
|
||||
total_amount = ref_doc.get("grand_total")
|
||||
if reference_doctype == "Dunning":
|
||||
total_amount = outstanding_amount = ref_doc.get("dunning_amount")
|
||||
exchange_rate = 1
|
||||
outstanding_amount = ref_doc.get("outstanding_amount")
|
||||
elif reference_doctype == "Dunning":
|
||||
total_amount = ref_doc.get("dunning_amount")
|
||||
exchange_rate = 1
|
||||
outstanding_amount = ref_doc.get("dunning_amount")
|
||||
|
||||
elif reference_doctype == "Journal Entry" and ref_doc.docstatus == 1:
|
||||
total_amount = ref_doc.get("total_amount")
|
||||
if ref_doc.multi_currency:
|
||||
@@ -1610,16 +1591,8 @@ def get_reference_details(reference_doctype, reference_name, party_account_curre
|
||||
else:
|
||||
exchange_rate = 1
|
||||
outstanding_amount = get_outstanding_on_journal_entry(reference_name)
|
||||
|
||||
elif reference_doctype != "Journal Entry":
|
||||
if ref_doc.doctype == "Expense Claim":
|
||||
total_amount = flt(ref_doc.total_sanctioned_amount) + flt(ref_doc.total_taxes_and_charges)
|
||||
elif ref_doc.doctype == "Employee Advance":
|
||||
total_amount = ref_doc.advance_amount
|
||||
exchange_rate = ref_doc.get("exchange_rate")
|
||||
if party_account_currency != ref_doc.currency:
|
||||
total_amount = flt(total_amount) * flt(exchange_rate)
|
||||
elif ref_doc.doctype == "Gratuity":
|
||||
total_amount = ref_doc.amount
|
||||
if not total_amount:
|
||||
if party_account_currency == company_currency:
|
||||
total_amount = ref_doc.base_grand_total
|
||||
@@ -1632,26 +1605,12 @@ def get_reference_details(reference_doctype, reference_name, party_account_curre
|
||||
exchange_rate = ref_doc.get("conversion_rate") or get_exchange_rate(
|
||||
party_account_currency, company_currency, ref_doc.posting_date
|
||||
)
|
||||
|
||||
if reference_doctype in ("Sales Invoice", "Purchase Invoice"):
|
||||
outstanding_amount = ref_doc.get("outstanding_amount")
|
||||
bill_no = ref_doc.get("bill_no")
|
||||
elif reference_doctype == "Expense Claim":
|
||||
outstanding_amount = (
|
||||
flt(ref_doc.get("total_sanctioned_amount"))
|
||||
+ flt(ref_doc.get("total_taxes_and_charges"))
|
||||
- flt(ref_doc.get("total_amount_reimbursed"))
|
||||
- flt(ref_doc.get("total_advance_amount"))
|
||||
)
|
||||
elif reference_doctype == "Employee Advance":
|
||||
outstanding_amount = flt(ref_doc.advance_amount) - flt(ref_doc.paid_amount)
|
||||
if party_account_currency != ref_doc.currency:
|
||||
outstanding_amount = flt(outstanding_amount) * flt(exchange_rate)
|
||||
if party_account_currency == company_currency:
|
||||
exchange_rate = 1
|
||||
elif reference_doctype == "Gratuity":
|
||||
outstanding_amount = ref_doc.amount - flt(ref_doc.paid_amount)
|
||||
else:
|
||||
outstanding_amount = flt(total_amount) - flt(ref_doc.advance_paid)
|
||||
|
||||
else:
|
||||
# Get the exchange rate based on the posting date of the ref doc.
|
||||
exchange_rate = get_exchange_rate(party_account_currency, company_currency, ref_doc.posting_date)
|
||||
@@ -1662,114 +1621,11 @@ def get_reference_details(reference_doctype, reference_name, party_account_curre
|
||||
"total_amount": flt(total_amount),
|
||||
"outstanding_amount": flt(outstanding_amount),
|
||||
"exchange_rate": flt(exchange_rate),
|
||||
"bill_no": bill_no,
|
||||
"bill_no": ref_doc.get("bill_no"),
|
||||
}
|
||||
)
|
||||
|
||||
|
||||
def get_amounts_based_on_reference_doctype(
|
||||
reference_doctype, ref_doc, party_account_currency, company_currency, reference_name
|
||||
):
|
||||
total_amount = outstanding_amount = exchange_rate = None
|
||||
if reference_doctype == "Fees":
|
||||
total_amount = ref_doc.get("grand_total")
|
||||
exchange_rate = 1
|
||||
outstanding_amount = ref_doc.get("outstanding_amount")
|
||||
elif reference_doctype == "Dunning":
|
||||
total_amount = ref_doc.get("dunning_amount")
|
||||
exchange_rate = 1
|
||||
outstanding_amount = ref_doc.get("dunning_amount")
|
||||
elif reference_doctype == "Journal Entry" and ref_doc.docstatus == 1:
|
||||
total_amount = ref_doc.get("total_amount")
|
||||
if ref_doc.multi_currency:
|
||||
exchange_rate = get_exchange_rate(
|
||||
party_account_currency, company_currency, ref_doc.posting_date
|
||||
)
|
||||
else:
|
||||
exchange_rate = 1
|
||||
outstanding_amount = get_outstanding_on_journal_entry(reference_name)
|
||||
|
||||
return total_amount, outstanding_amount, exchange_rate
|
||||
|
||||
|
||||
def get_amounts_based_on_ref_doc(
|
||||
reference_doctype, ref_doc, party_account_currency, company_currency
|
||||
):
|
||||
total_amount = outstanding_amount = exchange_rate = None
|
||||
if ref_doc.doctype == "Expense Claim":
|
||||
total_amount = flt(ref_doc.total_sanctioned_amount) + flt(ref_doc.total_taxes_and_charges)
|
||||
elif ref_doc.doctype == "Employee Advance":
|
||||
total_amount, exchange_rate = get_total_amount_exchange_rate_for_employee_advance(
|
||||
party_account_currency, ref_doc
|
||||
)
|
||||
|
||||
if not total_amount:
|
||||
total_amount, exchange_rate = get_total_amount_exchange_rate_base_on_currency(
|
||||
party_account_currency, company_currency, ref_doc
|
||||
)
|
||||
|
||||
if not exchange_rate:
|
||||
# Get the exchange rate from the original ref doc
|
||||
# or get it based on the posting date of the ref doc
|
||||
exchange_rate = ref_doc.get("conversion_rate") or get_exchange_rate(
|
||||
party_account_currency, company_currency, ref_doc.posting_date
|
||||
)
|
||||
|
||||
outstanding_amount, exchange_rate, bill_no = get_bill_no_and_update_amounts(
|
||||
reference_doctype, ref_doc, total_amount, exchange_rate, party_account_currency, company_currency
|
||||
)
|
||||
|
||||
return total_amount, outstanding_amount, exchange_rate, bill_no
|
||||
|
||||
|
||||
def get_total_amount_exchange_rate_for_employee_advance(party_account_currency, ref_doc):
|
||||
total_amount = ref_doc.advance_amount
|
||||
exchange_rate = ref_doc.get("exchange_rate")
|
||||
if party_account_currency != ref_doc.currency:
|
||||
total_amount = flt(total_amount) * flt(exchange_rate)
|
||||
|
||||
return total_amount, exchange_rate
|
||||
|
||||
|
||||
def get_total_amount_exchange_rate_base_on_currency(
|
||||
party_account_currency, company_currency, ref_doc
|
||||
):
|
||||
exchange_rate = None
|
||||
if party_account_currency == company_currency:
|
||||
total_amount = ref_doc.base_grand_total
|
||||
exchange_rate = 1
|
||||
else:
|
||||
total_amount = ref_doc.grand_total
|
||||
|
||||
return total_amount, exchange_rate
|
||||
|
||||
|
||||
def get_bill_no_and_update_amounts(
|
||||
reference_doctype, ref_doc, total_amount, exchange_rate, party_account_currency, company_currency
|
||||
):
|
||||
outstanding_amount = bill_no = None
|
||||
if reference_doctype in ("Sales Invoice", "Purchase Invoice"):
|
||||
outstanding_amount = ref_doc.get("outstanding_amount")
|
||||
bill_no = ref_doc.get("bill_no")
|
||||
elif reference_doctype == "Expense Claim":
|
||||
outstanding_amount = (
|
||||
flt(ref_doc.get("total_sanctioned_amount"))
|
||||
+ flt(ref_doc.get("total_taxes_and_charges"))
|
||||
- flt(ref_doc.get("total_amount_reimbursed"))
|
||||
- flt(ref_doc.get("total_advance_amount"))
|
||||
)
|
||||
elif reference_doctype == "Employee Advance":
|
||||
outstanding_amount = flt(ref_doc.advance_amount) - flt(ref_doc.paid_amount)
|
||||
if party_account_currency != ref_doc.currency:
|
||||
outstanding_amount = flt(outstanding_amount) * flt(exchange_rate)
|
||||
if party_account_currency == company_currency:
|
||||
exchange_rate = 1
|
||||
else:
|
||||
outstanding_amount = flt(total_amount) - flt(ref_doc.advance_paid)
|
||||
|
||||
return outstanding_amount, exchange_rate, bill_no
|
||||
|
||||
|
||||
@frappe.whitelist()
|
||||
def get_payment_entry(dt, dn, party_amount=None, bank_account=None, bank_amount=None):
|
||||
reference_doc = None
|
||||
@@ -1888,8 +1744,6 @@ def get_payment_entry(dt, dn, party_amount=None, bank_account=None, bank_amount=
|
||||
pe.set_missing_values()
|
||||
|
||||
if party_account and bank:
|
||||
if dt == "Employee Advance":
|
||||
reference_doc = doc
|
||||
pe.set_exchange_rate(ref_doc=reference_doc)
|
||||
pe.set_amounts()
|
||||
if discount_amount:
|
||||
@@ -1924,8 +1778,6 @@ def set_party_type(dt):
|
||||
party_type = "Customer"
|
||||
elif dt in ("Purchase Invoice", "Purchase Order"):
|
||||
party_type = "Supplier"
|
||||
elif dt in ("Expense Claim", "Employee Advance", "Gratuity"):
|
||||
party_type = "Employee"
|
||||
return party_type
|
||||
|
||||
|
||||
@@ -1936,12 +1788,6 @@ def set_party_account(dt, dn, doc, party_type):
|
||||
party_account = doc.credit_to
|
||||
elif dt == "Fees":
|
||||
party_account = doc.receivable_account
|
||||
elif dt == "Employee Advance":
|
||||
party_account = doc.advance_account
|
||||
elif dt == "Expense Claim":
|
||||
party_account = doc.payable_account
|
||||
elif dt == "Gratuity":
|
||||
party_account = doc.payable_account
|
||||
else:
|
||||
party_account = get_party_account(party_type, doc.get(party_type.lower()), doc.company)
|
||||
return party_account
|
||||
@@ -1976,24 +1822,12 @@ def set_grand_total_and_outstanding_amount(party_amount, dt, party_account_curre
|
||||
else:
|
||||
grand_total = doc.rounded_total or doc.grand_total
|
||||
outstanding_amount = doc.outstanding_amount
|
||||
elif dt in ("Expense Claim"):
|
||||
grand_total = doc.total_sanctioned_amount + doc.total_taxes_and_charges
|
||||
outstanding_amount = doc.grand_total - doc.total_amount_reimbursed
|
||||
elif dt == "Employee Advance":
|
||||
grand_total = flt(doc.advance_amount)
|
||||
outstanding_amount = flt(doc.advance_amount) - flt(doc.paid_amount)
|
||||
if party_account_currency != doc.currency:
|
||||
grand_total = flt(doc.advance_amount) * flt(doc.exchange_rate)
|
||||
outstanding_amount = (flt(doc.advance_amount) - flt(doc.paid_amount)) * flt(doc.exchange_rate)
|
||||
elif dt == "Fees":
|
||||
grand_total = doc.grand_total
|
||||
outstanding_amount = doc.outstanding_amount
|
||||
elif dt == "Dunning":
|
||||
grand_total = doc.grand_total
|
||||
outstanding_amount = doc.grand_total
|
||||
elif dt == "Gratuity":
|
||||
grand_total = doc.amount
|
||||
outstanding_amount = flt(doc.amount) - flt(doc.paid_amount)
|
||||
else:
|
||||
if party_account_currency == doc.company_currency:
|
||||
grand_total = flt(doc.get("base_rounded_total") or doc.base_grand_total)
|
||||
@@ -2015,8 +1849,6 @@ def set_paid_amount_and_received_amount(
|
||||
received_amount = bank_amount
|
||||
else:
|
||||
received_amount = paid_amount * doc.get("conversion_rate", 1)
|
||||
if dt == "Employee Advance":
|
||||
received_amount = paid_amount * doc.get("exchange_rate", 1)
|
||||
else:
|
||||
received_amount = abs(outstanding_amount)
|
||||
if bank_amount:
|
||||
@@ -2024,8 +1856,6 @@ def set_paid_amount_and_received_amount(
|
||||
else:
|
||||
# if party account currency and bank currency is different then populate paid amount as well
|
||||
paid_amount = received_amount * doc.get("conversion_rate", 1)
|
||||
if dt == "Employee Advance":
|
||||
paid_amount = received_amount * doc.get("exchange_rate", 1)
|
||||
|
||||
return paid_amount, received_amount
|
||||
|
||||
|
||||
@@ -19,8 +19,8 @@ from erpnext.accounts.doctype.sales_invoice.test_sales_invoice import (
|
||||
create_sales_invoice,
|
||||
create_sales_invoice_against_cost_center,
|
||||
)
|
||||
from erpnext.hr.doctype.expense_claim.test_expense_claim import make_expense_claim
|
||||
from erpnext.selling.doctype.sales_order.test_sales_order import make_sales_order
|
||||
from erpnext.setup.doctype.employee.test_employee import make_employee
|
||||
|
||||
test_dependencies = ["Item"]
|
||||
|
||||
@@ -297,31 +297,6 @@ class TestPaymentEntry(FrappeTestCase):
|
||||
self.assertEqual(flt(outstanding_amount), 250)
|
||||
self.assertEqual(status, "Unpaid")
|
||||
|
||||
def test_payment_entry_against_ec(self):
|
||||
|
||||
payable = frappe.get_cached_value("Company", "_Test Company", "default_payable_account")
|
||||
ec = make_expense_claim(payable, 300, 300, "_Test Company", "Travel Expenses - _TC")
|
||||
pe = get_payment_entry(
|
||||
"Expense Claim", ec.name, bank_account="_Test Bank USD - _TC", bank_amount=300
|
||||
)
|
||||
pe.reference_no = "1"
|
||||
pe.reference_date = "2016-01-01"
|
||||
pe.source_exchange_rate = 1
|
||||
pe.paid_to = payable
|
||||
pe.insert()
|
||||
pe.submit()
|
||||
|
||||
expected_gle = dict(
|
||||
(d[0], d) for d in [[payable, 300, 0, ec.name], ["_Test Bank USD - _TC", 0, 300, None]]
|
||||
)
|
||||
|
||||
self.validate_gl_entries(pe.name, expected_gle)
|
||||
|
||||
outstanding_amount = flt(
|
||||
frappe.db.get_value("Expense Claim", ec.name, "total_sanctioned_amount")
|
||||
) - flt(frappe.db.get_value("Expense Claim", ec.name, "total_amount_reimbursed"))
|
||||
self.assertEqual(outstanding_amount, 0)
|
||||
|
||||
def test_payment_entry_against_si_usd_to_inr(self):
|
||||
si = create_sales_invoice(
|
||||
customer="_Test Customer USD",
|
||||
@@ -762,6 +737,10 @@ class TestPaymentEntry(FrappeTestCase):
|
||||
|
||||
self.assertTrue("is on hold" in str(err.exception).lower())
|
||||
|
||||
def test_payment_entry_for_employee(self):
|
||||
employee = make_employee("test_payment_entry@salary.com", company="_Test Company")
|
||||
create_payment_entry(party_type="Employee", party=employee, save=True)
|
||||
|
||||
|
||||
def create_payment_entry(**args):
|
||||
payment_entry = frappe.new_doc("Payment Entry")
|
||||
|
||||
@@ -40,19 +40,22 @@
|
||||
"fieldname": "account",
|
||||
"fieldtype": "Link",
|
||||
"label": "Account",
|
||||
"options": "Account"
|
||||
"options": "Account",
|
||||
"search_index": 1
|
||||
},
|
||||
{
|
||||
"fieldname": "party_type",
|
||||
"fieldtype": "Link",
|
||||
"label": "Party Type",
|
||||
"options": "DocType"
|
||||
"options": "DocType",
|
||||
"search_index": 1
|
||||
},
|
||||
{
|
||||
"fieldname": "party",
|
||||
"fieldtype": "Dynamic Link",
|
||||
"label": "Party",
|
||||
"options": "party_type"
|
||||
"options": "party_type",
|
||||
"search_index": 1
|
||||
},
|
||||
{
|
||||
"fieldname": "voucher_type",
|
||||
@@ -114,7 +117,8 @@
|
||||
"fieldname": "company",
|
||||
"fieldtype": "Link",
|
||||
"label": "Company",
|
||||
"options": "Company"
|
||||
"options": "Company",
|
||||
"search_index": 1
|
||||
},
|
||||
{
|
||||
"fieldname": "cost_center",
|
||||
@@ -137,7 +141,7 @@
|
||||
"in_create": 1,
|
||||
"index_web_pages_for_search": 1,
|
||||
"links": [],
|
||||
"modified": "2022-05-30 19:04:55.532171",
|
||||
"modified": "2022-07-11 09:13:54.379168",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Accounts",
|
||||
"name": "Payment Ledger Entry",
|
||||
|
||||
@@ -147,3 +147,8 @@ class PaymentLedgerEntry(Document):
|
||||
update_voucher_outstanding(
|
||||
self.against_voucher_type, self.against_voucher_no, self.account, self.party_type, self.party
|
||||
)
|
||||
|
||||
|
||||
def on_doctype_update():
|
||||
frappe.db.add_index("Payment Ledger Entry", ["against_voucher_no", "against_voucher_type"])
|
||||
frappe.db.add_index("Payment Ledger Entry", ["voucher_no", "voucher_type"])
|
||||
|
||||
@@ -6,10 +6,10 @@ import json
|
||||
|
||||
import frappe
|
||||
from frappe import _
|
||||
from frappe.integrations.utils import get_payment_gateway_controller
|
||||
from frappe.model.document import Document
|
||||
from frappe.utils import flt, get_url, nowdate
|
||||
from frappe.utils.background_jobs import enqueue
|
||||
from payments.utils import get_payment_gateway_controller
|
||||
|
||||
from erpnext.accounts.doctype.payment_entry.payment_entry import (
|
||||
get_company_defaults,
|
||||
|
||||
@@ -10,10 +10,11 @@
|
||||
"fiscal_year",
|
||||
"amended_from",
|
||||
"company",
|
||||
"cost_center_wise_pnl",
|
||||
"column_break1",
|
||||
"closing_account_head",
|
||||
"remarks"
|
||||
"remarks",
|
||||
"gle_processing_status",
|
||||
"error_message"
|
||||
],
|
||||
"fields": [
|
||||
{
|
||||
@@ -86,17 +87,26 @@
|
||||
"reqd": 1
|
||||
},
|
||||
{
|
||||
"default": "0",
|
||||
"fieldname": "cost_center_wise_pnl",
|
||||
"fieldtype": "Check",
|
||||
"label": "Book Cost Center Wise Profit/Loss"
|
||||
"depends_on": "eval:doc.docstatus!=0",
|
||||
"fieldname": "gle_processing_status",
|
||||
"fieldtype": "Select",
|
||||
"label": "GL Entry Processing Status",
|
||||
"options": "In Progress\nCompleted\nFailed",
|
||||
"read_only": 1
|
||||
},
|
||||
{
|
||||
"depends_on": "eval:doc.gle_processing_status=='Failed'",
|
||||
"fieldname": "error_message",
|
||||
"fieldtype": "Text",
|
||||
"label": "Error Message",
|
||||
"read_only": 1
|
||||
}
|
||||
],
|
||||
"icon": "fa fa-file-text",
|
||||
"idx": 1,
|
||||
"is_submittable": 1,
|
||||
"links": [],
|
||||
"modified": "2021-05-20 15:27:37.210458",
|
||||
"modified": "2022-07-20 14:51:04.714154",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Accounts",
|
||||
"name": "Period Closing Voucher",
|
||||
|
||||
@@ -8,7 +8,6 @@ from frappe.utils import flt
|
||||
|
||||
from erpnext.accounts.doctype.accounting_dimension.accounting_dimension import (
|
||||
get_accounting_dimensions,
|
||||
get_dimensions,
|
||||
)
|
||||
from erpnext.accounts.utils import get_account_currency
|
||||
from erpnext.controllers.accounts_controller import AccountsController
|
||||
@@ -20,13 +19,28 @@ class PeriodClosingVoucher(AccountsController):
|
||||
self.validate_posting_date()
|
||||
|
||||
def on_submit(self):
|
||||
self.db_set("gle_processing_status", "In Progress")
|
||||
self.make_gl_entries()
|
||||
|
||||
def on_cancel(self):
|
||||
self.db_set("gle_processing_status", "In Progress")
|
||||
self.ignore_linked_doctypes = ("GL Entry", "Stock Ledger Entry")
|
||||
from erpnext.accounts.general_ledger import make_reverse_gl_entries
|
||||
|
||||
make_reverse_gl_entries(voucher_type="Period Closing Voucher", voucher_no=self.name)
|
||||
gle_count = frappe.db.count(
|
||||
"GL Entry",
|
||||
{"voucher_type": "Period Closing Voucher", "voucher_no": self.name, "is_cancelled": 0},
|
||||
)
|
||||
if gle_count > 5000:
|
||||
frappe.enqueue(
|
||||
make_reverse_gl_entries,
|
||||
voucher_type="Period Closing Voucher",
|
||||
voucher_no=self.name,
|
||||
queue="long",
|
||||
)
|
||||
frappe.msgprint(
|
||||
_("The GL Entries will be cancelled in the background, it can take a few minutes."), alert=True
|
||||
)
|
||||
else:
|
||||
make_reverse_gl_entries(voucher_type="Period Closing Voucher", voucher_no=self.name)
|
||||
|
||||
def validate_account_head(self):
|
||||
closing_account_type = frappe.db.get_value("Account", self.closing_account_head, "root_type")
|
||||
@@ -67,90 +81,80 @@ class PeriodClosingVoucher(AccountsController):
|
||||
def make_gl_entries(self):
|
||||
gl_entries = self.get_gl_entries()
|
||||
if gl_entries:
|
||||
from erpnext.accounts.general_ledger import make_gl_entries
|
||||
|
||||
make_gl_entries(gl_entries)
|
||||
if len(gl_entries) > 5000:
|
||||
frappe.enqueue(process_gl_entries, gl_entries=gl_entries, queue="long")
|
||||
frappe.msgprint(
|
||||
_("The GL Entries will be processed in the background, it can take a few minutes."),
|
||||
alert=True,
|
||||
)
|
||||
else:
|
||||
process_gl_entries(gl_entries)
|
||||
|
||||
def get_gl_entries(self):
|
||||
gl_entries = []
|
||||
pl_accounts = self.get_pl_balances()
|
||||
|
||||
for acc in pl_accounts:
|
||||
# pl account
|
||||
for acc in self.get_pl_balances_based_on_dimensions(group_by_account=True):
|
||||
if flt(acc.bal_in_company_currency):
|
||||
gl_entries.append(
|
||||
self.get_gl_dict(
|
||||
{
|
||||
"account": acc.account,
|
||||
"cost_center": acc.cost_center,
|
||||
"finance_book": acc.finance_book,
|
||||
"account_currency": acc.account_currency,
|
||||
"debit_in_account_currency": abs(flt(acc.bal_in_account_currency))
|
||||
if flt(acc.bal_in_account_currency) < 0
|
||||
else 0,
|
||||
"debit": abs(flt(acc.bal_in_company_currency))
|
||||
if flt(acc.bal_in_company_currency) < 0
|
||||
else 0,
|
||||
"credit_in_account_currency": abs(flt(acc.bal_in_account_currency))
|
||||
if flt(acc.bal_in_account_currency) > 0
|
||||
else 0,
|
||||
"credit": abs(flt(acc.bal_in_company_currency))
|
||||
if flt(acc.bal_in_company_currency) > 0
|
||||
else 0,
|
||||
},
|
||||
item=acc,
|
||||
)
|
||||
)
|
||||
gl_entries.append(self.get_gle_for_pl_account(acc))
|
||||
|
||||
if gl_entries:
|
||||
gle_for_net_pl_bal = self.get_pnl_gl_entry(pl_accounts)
|
||||
gl_entries += gle_for_net_pl_bal
|
||||
# closing liability account
|
||||
for acc in self.get_pl_balances_based_on_dimensions(group_by_account=False):
|
||||
if flt(acc.bal_in_company_currency):
|
||||
gl_entries.append(self.get_gle_for_closing_account(acc))
|
||||
|
||||
return gl_entries
|
||||
|
||||
def get_pnl_gl_entry(self, pl_accounts):
|
||||
company_cost_center = frappe.db.get_value("Company", self.company, "cost_center")
|
||||
gl_entries = []
|
||||
def get_gle_for_pl_account(self, acc):
|
||||
gl_entry = self.get_gl_dict(
|
||||
{
|
||||
"account": acc.account,
|
||||
"cost_center": acc.cost_center,
|
||||
"finance_book": acc.finance_book,
|
||||
"account_currency": acc.account_currency,
|
||||
"debit_in_account_currency": abs(flt(acc.bal_in_account_currency))
|
||||
if flt(acc.bal_in_account_currency) < 0
|
||||
else 0,
|
||||
"debit": abs(flt(acc.bal_in_company_currency)) if flt(acc.bal_in_company_currency) < 0 else 0,
|
||||
"credit_in_account_currency": abs(flt(acc.bal_in_account_currency))
|
||||
if flt(acc.bal_in_account_currency) > 0
|
||||
else 0,
|
||||
"credit": abs(flt(acc.bal_in_company_currency)) if flt(acc.bal_in_company_currency) > 0 else 0,
|
||||
},
|
||||
item=acc,
|
||||
)
|
||||
self.update_default_dimensions(gl_entry, acc)
|
||||
return gl_entry
|
||||
|
||||
for acc in pl_accounts:
|
||||
if flt(acc.bal_in_company_currency):
|
||||
cost_center = acc.cost_center if self.cost_center_wise_pnl else company_cost_center
|
||||
gl_entry = self.get_gl_dict(
|
||||
{
|
||||
"account": self.closing_account_head,
|
||||
"cost_center": cost_center,
|
||||
"finance_book": acc.finance_book,
|
||||
"account_currency": acc.account_currency,
|
||||
"debit_in_account_currency": abs(flt(acc.bal_in_account_currency))
|
||||
if flt(acc.bal_in_account_currency) > 0
|
||||
else 0,
|
||||
"debit": abs(flt(acc.bal_in_company_currency))
|
||||
if flt(acc.bal_in_company_currency) > 0
|
||||
else 0,
|
||||
"credit_in_account_currency": abs(flt(acc.bal_in_account_currency))
|
||||
if flt(acc.bal_in_account_currency) < 0
|
||||
else 0,
|
||||
"credit": abs(flt(acc.bal_in_company_currency))
|
||||
if flt(acc.bal_in_company_currency) < 0
|
||||
else 0,
|
||||
},
|
||||
item=acc,
|
||||
)
|
||||
def get_gle_for_closing_account(self, acc):
|
||||
gl_entry = self.get_gl_dict(
|
||||
{
|
||||
"account": self.closing_account_head,
|
||||
"cost_center": acc.cost_center,
|
||||
"finance_book": acc.finance_book,
|
||||
"account_currency": acc.account_currency,
|
||||
"debit_in_account_currency": abs(flt(acc.bal_in_account_currency))
|
||||
if flt(acc.bal_in_account_currency) > 0
|
||||
else 0,
|
||||
"debit": abs(flt(acc.bal_in_company_currency)) if flt(acc.bal_in_company_currency) > 0 else 0,
|
||||
"credit_in_account_currency": abs(flt(acc.bal_in_account_currency))
|
||||
if flt(acc.bal_in_account_currency) < 0
|
||||
else 0,
|
||||
"credit": abs(flt(acc.bal_in_company_currency)) if flt(acc.bal_in_company_currency) < 0 else 0,
|
||||
},
|
||||
item=acc,
|
||||
)
|
||||
self.update_default_dimensions(gl_entry, acc)
|
||||
return gl_entry
|
||||
|
||||
self.update_default_dimensions(gl_entry)
|
||||
|
||||
gl_entries.append(gl_entry)
|
||||
|
||||
return gl_entries
|
||||
|
||||
def update_default_dimensions(self, gl_entry):
|
||||
def update_default_dimensions(self, gl_entry, acc):
|
||||
if not self.accounting_dimensions:
|
||||
self.accounting_dimensions = get_accounting_dimensions()
|
||||
|
||||
_, default_dimensions = get_dimensions()
|
||||
for dimension in self.accounting_dimensions:
|
||||
gl_entry.update({dimension: default_dimensions.get(self.company, {}).get(dimension)})
|
||||
gl_entry.update({dimension: acc.get(dimension)})
|
||||
|
||||
def get_pl_balances(self):
|
||||
def get_pl_balances_based_on_dimensions(self, group_by_account=False):
|
||||
"""Get balance for dimension-wise pl accounts"""
|
||||
|
||||
dimension_fields = ["t1.cost_center", "t1.finance_book"]
|
||||
@@ -159,20 +163,56 @@ class PeriodClosingVoucher(AccountsController):
|
||||
for dimension in self.accounting_dimensions:
|
||||
dimension_fields.append("t1.{0}".format(dimension))
|
||||
|
||||
if group_by_account:
|
||||
dimension_fields.append("t1.account")
|
||||
|
||||
return frappe.db.sql(
|
||||
"""
|
||||
select
|
||||
t1.account, t2.account_currency, {dimension_fields},
|
||||
t2.account_currency,
|
||||
{dimension_fields},
|
||||
sum(t1.debit_in_account_currency) - sum(t1.credit_in_account_currency) as bal_in_account_currency,
|
||||
sum(t1.debit) - sum(t1.credit) as bal_in_company_currency
|
||||
from `tabGL Entry` t1, `tabAccount` t2
|
||||
where t1.is_cancelled = 0 and t1.account = t2.name and t2.report_type = 'Profit and Loss'
|
||||
and t2.docstatus < 2 and t2.company = %s
|
||||
and t1.posting_date between %s and %s
|
||||
group by t1.account, {dimension_fields}
|
||||
where
|
||||
t1.is_cancelled = 0
|
||||
and t1.account = t2.name
|
||||
and t2.report_type = 'Profit and Loss'
|
||||
and t2.docstatus < 2
|
||||
and t2.company = %s
|
||||
and t1.posting_date between %s and %s
|
||||
group by {dimension_fields}
|
||||
""".format(
|
||||
dimension_fields=", ".join(dimension_fields)
|
||||
),
|
||||
(self.company, self.get("year_start_date"), self.posting_date),
|
||||
as_dict=1,
|
||||
)
|
||||
|
||||
|
||||
def process_gl_entries(gl_entries):
|
||||
from erpnext.accounts.general_ledger import make_gl_entries
|
||||
|
||||
try:
|
||||
make_gl_entries(gl_entries, merge_entries=False)
|
||||
frappe.db.set_value(
|
||||
"Period Closing Voucher", gl_entries[0].get("voucher_no"), "gle_processing_status", "Completed"
|
||||
)
|
||||
except Exception as e:
|
||||
frappe.db.rollback()
|
||||
frappe.log_error(e)
|
||||
frappe.db.set_value(
|
||||
"Period Closing Voucher", gl_entries[0].get("voucher_no"), "gle_processing_status", "Failed"
|
||||
)
|
||||
|
||||
|
||||
def make_reverse_gl_entries(voucher_type, voucher_no):
|
||||
from erpnext.accounts.general_ledger import make_reverse_gl_entries
|
||||
|
||||
try:
|
||||
make_reverse_gl_entries(voucher_type=voucher_type, voucher_no=voucher_no)
|
||||
frappe.db.set_value("Period Closing Voucher", voucher_no, "gle_processing_status", "Completed")
|
||||
except Exception as e:
|
||||
frappe.db.rollback()
|
||||
frappe.log_error(e)
|
||||
frappe.db.set_value("Period Closing Voucher", voucher_no, "gle_processing_status", "Failed")
|
||||
|
||||
@@ -49,7 +49,7 @@ class TestPeriodClosingVoucher(unittest.TestCase):
|
||||
|
||||
expected_gle = (
|
||||
("Cost of Goods Sold - TPC", 0.0, 600.0),
|
||||
(surplus_account, 600.0, 400.0),
|
||||
(surplus_account, 200.0, 0.0),
|
||||
("Sales - TPC", 400.0, 0.0),
|
||||
)
|
||||
|
||||
@@ -59,7 +59,8 @@ class TestPeriodClosingVoucher(unittest.TestCase):
|
||||
""",
|
||||
(pcv.name),
|
||||
)
|
||||
|
||||
pcv.reload()
|
||||
self.assertEqual(pcv.gle_processing_status, "Completed")
|
||||
self.assertEqual(pcv_gle, expected_gle)
|
||||
|
||||
def test_cost_center_wise_posting(self):
|
||||
@@ -93,7 +94,6 @@ class TestPeriodClosingVoucher(unittest.TestCase):
|
||||
)
|
||||
|
||||
pcv = self.make_period_closing_voucher(submit=False)
|
||||
pcv.cost_center_wise_pnl = 1
|
||||
pcv.save()
|
||||
pcv.submit()
|
||||
surplus_account = pcv.closing_account_head
|
||||
@@ -114,7 +114,17 @@ class TestPeriodClosingVoucher(unittest.TestCase):
|
||||
(pcv.name),
|
||||
)
|
||||
|
||||
self.assertEqual(pcv_gle, expected_gle)
|
||||
self.assertSequenceEqual(pcv_gle, expected_gle)
|
||||
|
||||
pcv.reload()
|
||||
pcv.cancel()
|
||||
|
||||
self.assertFalse(
|
||||
frappe.db.get_value(
|
||||
"GL Entry",
|
||||
{"voucher_type": "Period Closing Voucher", "voucher_no": pcv.name, "is_cancelled": 0},
|
||||
)
|
||||
)
|
||||
|
||||
def test_period_closing_with_finance_book_entries(self):
|
||||
frappe.db.sql("delete from `tabGL Entry` where company='Test PCV Company'")
|
||||
@@ -165,7 +175,7 @@ class TestPeriodClosingVoucher(unittest.TestCase):
|
||||
(pcv.name),
|
||||
)
|
||||
|
||||
self.assertEqual(pcv_gle, expected_gle)
|
||||
self.assertSequenceEqual(pcv_gle, expected_gle)
|
||||
|
||||
def make_period_closing_voucher(self, submit=True):
|
||||
surplus_account = create_account()
|
||||
|
||||
@@ -222,9 +222,6 @@ class POSInvoice(SalesInvoice):
|
||||
from erpnext.stock.stock_ledger import is_negative_stock_allowed
|
||||
|
||||
for d in self.get("items"):
|
||||
is_service_item = not (frappe.db.get_value("Item", d.get("item_code"), "is_stock_item"))
|
||||
if is_service_item:
|
||||
return
|
||||
if d.serial_no:
|
||||
self.validate_pos_reserved_serial_nos(d)
|
||||
self.validate_delivered_serial_nos(d)
|
||||
|
||||
@@ -9,7 +9,7 @@ from frappe import _
|
||||
from frappe.core.page.background_jobs.background_jobs import get_info
|
||||
from frappe.model.document import Document
|
||||
from frappe.model.mapper import map_child_doc, map_doc
|
||||
from frappe.utils import flt, getdate, nowdate
|
||||
from frappe.utils import cint, flt, getdate, nowdate
|
||||
from frappe.utils.background_jobs import enqueue
|
||||
from frappe.utils.scheduler import is_scheduler_inactive
|
||||
|
||||
@@ -219,6 +219,9 @@ class POSInvoiceMergeLog(Document):
|
||||
invoice.taxes_and_charges = None
|
||||
invoice.ignore_pricing_rule = 1
|
||||
invoice.customer = self.customer
|
||||
invoice.disable_rounded_total = cint(
|
||||
frappe.db.get_value("POS Profile", invoice.pos_profile, "disable_rounded_total")
|
||||
)
|
||||
|
||||
if self.merge_invoices_based_on == "Customer Group":
|
||||
invoice.flags.ignore_pos_profile = True
|
||||
|
||||
@@ -44,6 +44,7 @@
|
||||
"write_off_account",
|
||||
"write_off_cost_center",
|
||||
"account_for_change_amount",
|
||||
"disable_rounded_total",
|
||||
"column_break_23",
|
||||
"income_account",
|
||||
"expense_account",
|
||||
@@ -358,6 +359,13 @@
|
||||
"fieldname": "validate_stock_on_save",
|
||||
"fieldtype": "Check",
|
||||
"label": "Validate Stock on Save"
|
||||
},
|
||||
{
|
||||
"default": "0",
|
||||
"description": "If enabled, the consolidated invoices will have rounded total disabled",
|
||||
"fieldname": "disable_rounded_total",
|
||||
"fieldtype": "Check",
|
||||
"label": "Disable Rounded Total"
|
||||
}
|
||||
],
|
||||
"icon": "icon-cog",
|
||||
@@ -385,7 +393,7 @@
|
||||
"link_fieldname": "pos_profile"
|
||||
}
|
||||
],
|
||||
"modified": "2022-03-21 13:29:28.480533",
|
||||
"modified": "2022-07-21 11:16:46.911173",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Accounts",
|
||||
"name": "POS Profile",
|
||||
|
||||
@@ -162,6 +162,7 @@ class PurchaseInvoice(BuyingController):
|
||||
if tds_category and not for_validate:
|
||||
self.apply_tds = 1
|
||||
self.tax_withholding_category = tds_category
|
||||
self.set_onload("supplier_tds", tds_category)
|
||||
|
||||
super(PurchaseInvoice, self).set_missing_values(for_validate)
|
||||
|
||||
|
||||
@@ -1,38 +0,0 @@
|
||||
{
|
||||
"actions": [],
|
||||
"creation": "2016-07-27 17:24:24.956896",
|
||||
"doctype": "DocType",
|
||||
"editable_grid": 1,
|
||||
"engine": "InnoDB",
|
||||
"field_order": [
|
||||
"company",
|
||||
"account"
|
||||
],
|
||||
"fields": [
|
||||
{
|
||||
"fieldname": "company",
|
||||
"fieldtype": "Link",
|
||||
"in_list_view": 1,
|
||||
"label": "Company",
|
||||
"options": "Company"
|
||||
},
|
||||
{
|
||||
"description": "Default Bank / Cash account will be automatically updated in Salary Journal Entry when this mode is selected.",
|
||||
"fieldname": "account",
|
||||
"fieldtype": "Link",
|
||||
"in_list_view": 1,
|
||||
"label": "Account",
|
||||
"options": "Account"
|
||||
}
|
||||
],
|
||||
"istable": 1,
|
||||
"links": [],
|
||||
"modified": "2020-10-18 17:57:57.110257",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Accounts",
|
||||
"name": "Salary Component Account",
|
||||
"owner": "Administrator",
|
||||
"permissions": [],
|
||||
"sort_field": "modified",
|
||||
"sort_order": "DESC"
|
||||
}
|
||||
@@ -1,9 +0,0 @@
|
||||
# Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and contributors
|
||||
# For license information, please see license.txt
|
||||
|
||||
|
||||
from frappe.model.document import Document
|
||||
|
||||
|
||||
class SalaryComponentAccount(Document):
|
||||
pass
|
||||
@@ -412,7 +412,7 @@
|
||||
},
|
||||
{
|
||||
"default": "0",
|
||||
"depends_on": "eval: doc.is_return && doc.return_against",
|
||||
"depends_on": "eval: doc.is_return",
|
||||
"fieldname": "update_billed_amount_in_sales_order",
|
||||
"fieldtype": "Check",
|
||||
"hide_days": 1,
|
||||
@@ -2022,7 +2022,7 @@
|
||||
"link_fieldname": "consolidated_invoice"
|
||||
}
|
||||
],
|
||||
"modified": "2022-06-16 16:22:44.870575",
|
||||
"modified": "2022-07-11 17:43:56.435382",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Accounts",
|
||||
"name": "Sales Invoice",
|
||||
|
||||
@@ -168,6 +168,7 @@ def get_cost_center_allocation_data(company, posting_date):
|
||||
def merge_similar_entries(gl_map, precision=None):
|
||||
merged_gl_map = []
|
||||
accounting_dimensions = get_accounting_dimensions()
|
||||
|
||||
for entry in gl_map:
|
||||
# if there is already an entry in this account then just add it
|
||||
# to that entry
|
||||
@@ -298,9 +299,10 @@ def make_entry(args, adv_adj, update_outstanding, from_repost=False):
|
||||
gle.flags.from_repost = from_repost
|
||||
gle.flags.adv_adj = adv_adj
|
||||
gle.flags.update_outstanding = update_outstanding or "Yes"
|
||||
gle.flags.notify_update = False
|
||||
gle.submit()
|
||||
|
||||
if not from_repost:
|
||||
if not from_repost and gle.voucher_type != "Period Closing Voucher":
|
||||
validate_expense_against_budget(args)
|
||||
|
||||
|
||||
|
||||
@@ -136,6 +136,11 @@ frappe.query_reports["Accounts Payable"] = {
|
||||
"label": __("Tax Id"),
|
||||
"fieldtype": "Data",
|
||||
"hidden": 1
|
||||
},
|
||||
{
|
||||
"fieldname": "show_future_payments",
|
||||
"label": __("Show Future Payments"),
|
||||
"fieldtype": "Check",
|
||||
}
|
||||
],
|
||||
|
||||
|
||||
@@ -164,6 +164,8 @@ class ReceivablePayableReport(object):
|
||||
"range3",
|
||||
"range4",
|
||||
"range5",
|
||||
"future_amount",
|
||||
"remaining_balance"
|
||||
]
|
||||
|
||||
def get_voucher_balance(self, ple):
|
||||
@@ -545,7 +547,7 @@ class ReceivablePayableReport(object):
|
||||
jea.party,
|
||||
jea.party_type,
|
||||
je.posting_date as future_date,
|
||||
sum({0}) as future_amount,
|
||||
sum('{0}') as future_amount,
|
||||
je.cheque_no as future_ref
|
||||
from
|
||||
`tabJournal Entry` as je inner join `tabJournal Entry Account` as jea
|
||||
|
||||
@@ -198,12 +198,10 @@ def get_loan_entries(filters):
|
||||
amount_field = (loan_doc.disbursed_amount).as_("credit")
|
||||
posting_date = (loan_doc.disbursement_date).as_("posting_date")
|
||||
account = loan_doc.disbursement_account
|
||||
salary_condition = loan_doc.docstatus == 1
|
||||
else:
|
||||
amount_field = (loan_doc.amount_paid).as_("debit")
|
||||
posting_date = (loan_doc.posting_date).as_("posting_date")
|
||||
account = loan_doc.payment_account
|
||||
salary_condition = loan_doc.repay_from_salary == 0
|
||||
|
||||
query = (
|
||||
frappe.qb.from_(loan_doc)
|
||||
@@ -216,12 +214,14 @@ def get_loan_entries(filters):
|
||||
posting_date,
|
||||
)
|
||||
.where(loan_doc.docstatus == 1)
|
||||
.where(salary_condition)
|
||||
.where(account == filters.get("account"))
|
||||
.where(posting_date <= getdate(filters.get("report_date")))
|
||||
.where(ifnull(loan_doc.clearance_date, "4000-01-01") > getdate(filters.get("report_date")))
|
||||
)
|
||||
|
||||
if doctype == "Loan Repayment" and frappe.db.has_column("Loan Repayment", "repay_from_salary"):
|
||||
query = query.where((loan_doc.repay_from_salary == 0))
|
||||
|
||||
entries = query.run(as_dict=1)
|
||||
loan_docs.extend(entries)
|
||||
|
||||
@@ -267,23 +267,24 @@ def get_loan_amount(filters):
|
||||
amount_field = Sum(loan_doc.disbursed_amount)
|
||||
posting_date = (loan_doc.disbursement_date).as_("posting_date")
|
||||
account = loan_doc.disbursement_account
|
||||
salary_condition = loan_doc.docstatus == 1
|
||||
else:
|
||||
amount_field = Sum(loan_doc.amount_paid)
|
||||
posting_date = (loan_doc.posting_date).as_("posting_date")
|
||||
account = loan_doc.payment_account
|
||||
salary_condition = loan_doc.repay_from_salary == 0
|
||||
amount = (
|
||||
|
||||
query = (
|
||||
frappe.qb.from_(loan_doc)
|
||||
.select(amount_field)
|
||||
.where(loan_doc.docstatus == 1)
|
||||
.where(salary_condition)
|
||||
.where(account == filters.get("account"))
|
||||
.where(posting_date > getdate(filters.get("report_date")))
|
||||
.where(ifnull(loan_doc.clearance_date, "4000-01-01") <= getdate(filters.get("report_date")))
|
||||
.run()[0][0]
|
||||
)
|
||||
|
||||
if doctype == "Loan Repayment" and frappe.db.has_column("Loan Repayment", "repay_from_salary"):
|
||||
query = query.where((loan_doc.repay_from_salary == 0))
|
||||
|
||||
amount = query.run()[0][0]
|
||||
total_amount += flt(amount)
|
||||
|
||||
return total_amount
|
||||
|
||||
@@ -0,0 +1,40 @@
|
||||
# Copyright (c) 2022, Frappe Technologies Pvt. Ltd. and Contributors
|
||||
# See license.txt
|
||||
|
||||
import frappe
|
||||
from frappe.tests.utils import FrappeTestCase
|
||||
|
||||
from erpnext.accounts.doctype.bank_transaction.test_bank_transaction import (
|
||||
create_loan_and_repayment,
|
||||
)
|
||||
from erpnext.accounts.report.bank_reconciliation_statement.bank_reconciliation_statement import (
|
||||
execute,
|
||||
)
|
||||
from erpnext.loan_management.doctype.loan.test_loan import create_loan_accounts
|
||||
|
||||
|
||||
class TestBankReconciliationStatement(FrappeTestCase):
|
||||
def setUp(self):
|
||||
for dt in [
|
||||
"Loan Repayment",
|
||||
"Loan Disbursement",
|
||||
"Journal Entry",
|
||||
"Journal Entry Account",
|
||||
"Payment Entry",
|
||||
]:
|
||||
frappe.db.delete(dt)
|
||||
|
||||
def test_loan_entries_in_bank_reco_statement(self):
|
||||
create_loan_accounts()
|
||||
repayment_entry = create_loan_and_repayment()
|
||||
|
||||
filters = frappe._dict(
|
||||
{
|
||||
"company": "Test Company",
|
||||
"account": "Payment Account - _TC",
|
||||
"report_date": "2018-10-30",
|
||||
}
|
||||
)
|
||||
result = execute(filters)
|
||||
|
||||
self.assertEqual(result[1][0].payment_entry, repayment_entry.name)
|
||||
@@ -8,11 +8,11 @@ from frappe import _
|
||||
|
||||
def execute(filters=None):
|
||||
validate_filters(filters)
|
||||
tds_docs, tds_accounts, tax_category_map = get_tds_docs(filters)
|
||||
tds_docs, tds_accounts, tax_category_map, journal_entry_party_map = get_tds_docs(filters)
|
||||
|
||||
columns = get_columns(filters)
|
||||
|
||||
res = get_result(filters, tds_docs, tds_accounts, tax_category_map)
|
||||
res = get_result(filters, tds_docs, tds_accounts, tax_category_map, journal_entry_party_map)
|
||||
return columns, res
|
||||
|
||||
|
||||
@@ -22,10 +22,11 @@ def validate_filters(filters):
|
||||
frappe.throw(_("From Date must be before To Date"))
|
||||
|
||||
|
||||
def get_result(filters, tds_docs, tds_accounts, tax_category_map):
|
||||
def get_result(filters, tds_docs, tds_accounts, tax_category_map, journal_entry_party_map):
|
||||
supplier_map = get_supplier_pan_map()
|
||||
tax_rate_map = get_tax_rate_map(filters)
|
||||
gle_map = get_gle_map(tds_docs)
|
||||
print(journal_entry_party_map)
|
||||
|
||||
out = []
|
||||
for name, details in gle_map.items():
|
||||
@@ -38,6 +39,11 @@ def get_result(filters, tds_docs, tds_accounts, tax_category_map):
|
||||
posting_date = entry.posting_date
|
||||
voucher_type = entry.voucher_type
|
||||
|
||||
if voucher_type == "Journal Entry":
|
||||
suppliers = journal_entry_party_map.get(name)
|
||||
if suppliers:
|
||||
supplier = suppliers[0]
|
||||
|
||||
if not tax_withholding_category:
|
||||
tax_withholding_category = supplier_map.get(supplier, {}).get("tax_withholding_category")
|
||||
rate = tax_rate_map.get(tax_withholding_category)
|
||||
@@ -176,6 +182,7 @@ def get_tds_docs(filters):
|
||||
journal_entries = []
|
||||
tax_category_map = {}
|
||||
or_filters = {}
|
||||
journal_entry_party_map = {}
|
||||
bank_accounts = frappe.get_all("Account", {"is_group": 0, "account_type": "Bank"}, pluck="name")
|
||||
|
||||
tds_accounts = frappe.get_all(
|
||||
@@ -218,9 +225,24 @@ def get_tds_docs(filters):
|
||||
get_tax_category_map(payment_entries, "Payment Entry", tax_category_map)
|
||||
|
||||
if journal_entries:
|
||||
journal_entry_party_map = get_journal_entry_party_map(journal_entries)
|
||||
get_tax_category_map(journal_entries, "Journal Entry", tax_category_map)
|
||||
|
||||
return tds_documents, tds_accounts, tax_category_map
|
||||
return tds_documents, tds_accounts, tax_category_map, journal_entry_party_map
|
||||
|
||||
|
||||
def get_journal_entry_party_map(journal_entries):
|
||||
journal_entry_party_map = {}
|
||||
for d in frappe.db.get_all(
|
||||
"Journal Entry Account",
|
||||
{"parent": ("in", journal_entries), "party_type": "Supplier", "party": ("is", "set")},
|
||||
["parent", "party"],
|
||||
):
|
||||
if d.parent not in journal_entry_party_map:
|
||||
journal_entry_party_map[d.parent] = []
|
||||
journal_entry_party_map[d.parent].append(d.party)
|
||||
|
||||
return journal_entry_party_map
|
||||
|
||||
|
||||
def get_tax_category_map(vouchers, doctype, tax_category_map):
|
||||
|
||||
@@ -1,13 +0,0 @@
|
||||
// Copyright (c) 2016, Frappe Technologies Pvt. Ltd. and contributors
|
||||
// For license information, please see license.txt
|
||||
|
||||
frappe.query_reports["Unpaid Expense Claim"] = {
|
||||
"filters": [
|
||||
{
|
||||
"fieldname": "employee",
|
||||
"label": __("Employee"),
|
||||
"fieldtype": "Link",
|
||||
"options": "Employee"
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -1,29 +0,0 @@
|
||||
{
|
||||
"add_total_row": 0,
|
||||
"apply_user_permissions": 1,
|
||||
"creation": "2017-01-04 16:26:18.309717",
|
||||
"disabled": 0,
|
||||
"docstatus": 0,
|
||||
"doctype": "Report",
|
||||
"idx": 2,
|
||||
"is_standard": "Yes",
|
||||
"modified": "2017-02-24 19:59:29.747039",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Accounts",
|
||||
"name": "Unpaid Expense Claim",
|
||||
"owner": "Administrator",
|
||||
"ref_doctype": "Expense Claim",
|
||||
"report_name": "Unpaid Expense Claim",
|
||||
"report_type": "Script Report",
|
||||
"roles": [
|
||||
{
|
||||
"role": "HR Manager"
|
||||
},
|
||||
{
|
||||
"role": "Expense Approver"
|
||||
},
|
||||
{
|
||||
"role": "HR User"
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -1,49 +0,0 @@
|
||||
# Copyright (c) 2013, Frappe Technologies Pvt. Ltd. and contributors
|
||||
# For license information, please see license.txt
|
||||
|
||||
|
||||
import frappe
|
||||
from frappe import _
|
||||
|
||||
|
||||
def execute(filters=None):
|
||||
columns, data = [], []
|
||||
columns = get_columns()
|
||||
data = get_unclaimed_expese_claims(filters)
|
||||
return columns, data
|
||||
|
||||
|
||||
def get_columns():
|
||||
return [
|
||||
_("Employee") + ":Link/Employee:120",
|
||||
_("Employee Name") + "::120",
|
||||
_("Expense Claim") + ":Link/Expense Claim:120",
|
||||
_("Sanctioned Amount") + ":Currency:120",
|
||||
_("Paid Amount") + ":Currency:120",
|
||||
_("Outstanding Amount") + ":Currency:150",
|
||||
]
|
||||
|
||||
|
||||
def get_unclaimed_expese_claims(filters):
|
||||
cond = "1=1"
|
||||
if filters.get("employee"):
|
||||
cond = "ec.employee = %(employee)s"
|
||||
|
||||
return frappe.db.sql(
|
||||
"""
|
||||
select
|
||||
ec.employee, ec.employee_name, ec.name, ec.total_sanctioned_amount, ec.total_amount_reimbursed,
|
||||
sum(gle.credit_in_account_currency - gle.debit_in_account_currency) as outstanding_amt
|
||||
from
|
||||
`tabExpense Claim` ec, `tabGL Entry` gle
|
||||
where
|
||||
gle.against_voucher_type = "Expense Claim" and gle.against_voucher = ec.name
|
||||
and gle.party is not null and ec.docstatus = 1 and ec.is_paid = 0 and {cond} group by ec.name
|
||||
having
|
||||
outstanding_amt > 0
|
||||
""".format(
|
||||
cond=cond
|
||||
),
|
||||
filters,
|
||||
as_list=1,
|
||||
)
|
||||
@@ -420,7 +420,7 @@ def add_cc(args=None):
|
||||
return cc.name
|
||||
|
||||
|
||||
def reconcile_against_document(args):
|
||||
def reconcile_against_document(args): # nosemgrep
|
||||
"""
|
||||
Cancel PE or JV, Update against document, split if required and resubmit
|
||||
"""
|
||||
@@ -461,7 +461,8 @@ def reconcile_against_document(args):
|
||||
frappe.flags.ignore_party_validation = False
|
||||
|
||||
if entry.voucher_type in ("Payment Entry", "Journal Entry"):
|
||||
doc.update_expense_claim()
|
||||
if hasattr(doc, "update_expense_claim"):
|
||||
doc.update_expense_claim()
|
||||
|
||||
|
||||
def check_if_advance_entry_modified(args):
|
||||
|
||||
@@ -40,7 +40,6 @@
|
||||
"purchase_date",
|
||||
"section_break_23",
|
||||
"calculate_depreciation",
|
||||
"allow_monthly_depreciation",
|
||||
"column_break_33",
|
||||
"opening_accumulated_depreciation",
|
||||
"number_of_depreciations_booked",
|
||||
@@ -456,13 +455,6 @@
|
||||
"fieldname": "dimension_col_break",
|
||||
"fieldtype": "Column Break"
|
||||
},
|
||||
{
|
||||
"default": "0",
|
||||
"depends_on": "calculate_depreciation",
|
||||
"fieldname": "allow_monthly_depreciation",
|
||||
"fieldtype": "Check",
|
||||
"label": "Allow Monthly Depreciation"
|
||||
},
|
||||
{
|
||||
"collapsible": 1,
|
||||
"collapsible_depends_on": "is_existing_asset",
|
||||
@@ -518,7 +510,7 @@
|
||||
"link_fieldname": "asset"
|
||||
}
|
||||
],
|
||||
"modified": "2022-01-30 20:19:24.680027",
|
||||
"modified": "2022-07-20 10:15:12.887372",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Assets",
|
||||
"name": "Asset",
|
||||
|
||||
@@ -343,51 +343,13 @@ class Asset(AccountsController):
|
||||
skip_row = True
|
||||
|
||||
if depreciation_amount > 0:
|
||||
# With monthly depreciation, each depreciation is divided by months remaining until next date
|
||||
if self.allow_monthly_depreciation:
|
||||
# month range is 1 to 12
|
||||
# In pro rata case, for first and last depreciation, month range would be different
|
||||
month_range = (
|
||||
months
|
||||
if (has_pro_rata and n == 0)
|
||||
or (has_pro_rata and n == cint(number_of_pending_depreciations) - 1)
|
||||
else finance_book.frequency_of_depreciation
|
||||
)
|
||||
|
||||
for r in range(month_range):
|
||||
if has_pro_rata and n == 0:
|
||||
# For first entry of monthly depr
|
||||
if r == 0:
|
||||
days_until_first_depr = date_diff(monthly_schedule_date, self.available_for_use_date)
|
||||
per_day_amt = depreciation_amount / days
|
||||
depreciation_amount_for_current_month = per_day_amt * days_until_first_depr
|
||||
depreciation_amount -= depreciation_amount_for_current_month
|
||||
date = monthly_schedule_date
|
||||
amount = depreciation_amount_for_current_month
|
||||
else:
|
||||
date = add_months(monthly_schedule_date, r)
|
||||
amount = depreciation_amount / (month_range - 1)
|
||||
elif (has_pro_rata and n == cint(number_of_pending_depreciations) - 1) and r == cint(
|
||||
month_range
|
||||
) - 1:
|
||||
# For last entry of monthly depr
|
||||
date = last_schedule_date
|
||||
amount = depreciation_amount / month_range
|
||||
else:
|
||||
date = add_months(monthly_schedule_date, r)
|
||||
amount = depreciation_amount / month_range
|
||||
|
||||
self._add_depreciation_row(
|
||||
date, amount, finance_book.depreciation_method, finance_book.finance_book, finance_book.idx
|
||||
)
|
||||
else:
|
||||
self._add_depreciation_row(
|
||||
schedule_date,
|
||||
depreciation_amount,
|
||||
finance_book.depreciation_method,
|
||||
finance_book.finance_book,
|
||||
finance_book.idx,
|
||||
)
|
||||
self._add_depreciation_row(
|
||||
schedule_date,
|
||||
depreciation_amount,
|
||||
finance_book.depreciation_method,
|
||||
finance_book.finance_book,
|
||||
finance_book.idx,
|
||||
)
|
||||
|
||||
def _add_depreciation_row(
|
||||
self, schedule_date, depreciation_amount, depreciation_method, finance_book, finance_book_id
|
||||
@@ -854,10 +816,8 @@ class Asset(AccountsController):
|
||||
return args.get("rate_of_depreciation")
|
||||
|
||||
value = flt(args.get("expected_value_after_useful_life")) / flt(self.gross_purchase_amount)
|
||||
|
||||
depreciation_rate = math.pow(value, 1.0 / flt(args.get("total_number_of_depreciations"), 2))
|
||||
|
||||
return 100 * (1 - flt(depreciation_rate, float_precision))
|
||||
return flt((100 * (1 - depreciation_rate)), float_precision)
|
||||
|
||||
def get_pro_rata_amt(self, row, depreciation_amount, from_date, to_date):
|
||||
days = date_diff(to_date, from_date)
|
||||
|
||||
@@ -133,7 +133,7 @@ class TestAsset(AssetSetup):
|
||||
order by account""",
|
||||
pi.name,
|
||||
)
|
||||
self.assertEqual(gle, expected_gle)
|
||||
self.assertSequenceEqual(gle, expected_gle)
|
||||
|
||||
pi.cancel()
|
||||
asset.cancel()
|
||||
@@ -208,7 +208,7 @@ class TestAsset(AssetSetup):
|
||||
order by account""",
|
||||
asset.journal_entry_for_scrap,
|
||||
)
|
||||
self.assertEqual(gle, expected_gle)
|
||||
self.assertSequenceEqual(gle, expected_gle)
|
||||
|
||||
restore_asset(asset.name)
|
||||
|
||||
@@ -253,7 +253,7 @@ class TestAsset(AssetSetup):
|
||||
si.name,
|
||||
)
|
||||
|
||||
self.assertEqual(gle, expected_gle)
|
||||
self.assertSequenceEqual(gle, expected_gle)
|
||||
|
||||
si.cancel()
|
||||
self.assertEqual(frappe.db.get_value("Asset", asset.name, "status"), "Partially Depreciated")
|
||||
@@ -361,7 +361,7 @@ class TestAsset(AssetSetup):
|
||||
pr.name,
|
||||
)
|
||||
|
||||
self.assertEqual(pr_gle, expected_gle)
|
||||
self.assertSequenceEqual(pr_gle, expected_gle)
|
||||
|
||||
pi = make_invoice(pr.name)
|
||||
pi.submit()
|
||||
@@ -381,7 +381,7 @@ class TestAsset(AssetSetup):
|
||||
pi.name,
|
||||
)
|
||||
|
||||
self.assertEqual(pi_gle, expected_gle)
|
||||
self.assertSequenceEqual(pi_gle, expected_gle)
|
||||
|
||||
asset = frappe.db.get_value("Asset", {"purchase_receipt": pr.name, "docstatus": 0}, "name")
|
||||
|
||||
@@ -414,7 +414,7 @@ class TestAsset(AssetSetup):
|
||||
asset_doc.name,
|
||||
)
|
||||
|
||||
self.assertEqual(gle, expected_gle)
|
||||
self.assertSequenceEqual(gle, expected_gle)
|
||||
|
||||
def test_asset_cwip_toggling_cases(self):
|
||||
cwip = frappe.db.get_value("Asset Category", "Computers", "enable_cwip_accounting")
|
||||
@@ -721,12 +721,12 @@ class TestDepreciationMethods(AssetSetup):
|
||||
)
|
||||
|
||||
expected_schedules = [
|
||||
["2022-02-28", 645.0, 645.0],
|
||||
["2022-03-31", 1206.8, 1851.8],
|
||||
["2022-04-30", 1051.12, 2902.92],
|
||||
["2022-05-31", 915.52, 3818.44],
|
||||
["2022-06-30", 797.42, 4615.86],
|
||||
["2022-07-15", 384.14, 5000.0],
|
||||
["2022-02-28", 647.25, 647.25],
|
||||
["2022-03-31", 1210.71, 1857.96],
|
||||
["2022-04-30", 1053.99, 2911.95],
|
||||
["2022-05-31", 917.55, 3829.5],
|
||||
["2022-06-30", 798.77, 4628.27],
|
||||
["2022-07-15", 371.73, 5000.0],
|
||||
]
|
||||
|
||||
schedules = [
|
||||
@@ -737,7 +737,6 @@ class TestDepreciationMethods(AssetSetup):
|
||||
]
|
||||
for d in asset.get("schedules")
|
||||
]
|
||||
|
||||
self.assertEqual(schedules, expected_schedules)
|
||||
|
||||
|
||||
@@ -1288,7 +1287,7 @@ class TestDepreciationBasics(AssetSetup):
|
||||
asset.name,
|
||||
)
|
||||
|
||||
self.assertEqual(gle, expected_gle)
|
||||
self.assertSequenceEqual(gle, expected_gle)
|
||||
self.assertEqual(asset.get("value_after_depreciation"), 0)
|
||||
|
||||
def test_expected_value_change(self):
|
||||
|
||||
@@ -7,7 +7,7 @@ import frappe
|
||||
from frappe.utils import now
|
||||
|
||||
from erpnext.assets.doctype.asset.test_asset import create_asset_data
|
||||
from erpnext.hr.doctype.employee.test_employee import make_employee
|
||||
from erpnext.setup.doctype.employee.test_employee import make_employee
|
||||
from erpnext.stock.doctype.purchase_receipt.test_purchase_receipt import make_purchase_receipt
|
||||
|
||||
|
||||
|
||||
@@ -91,7 +91,7 @@ class TestAssetValueAdjustment(unittest.TestCase):
|
||||
adj_doc.journal_entry,
|
||||
)
|
||||
|
||||
self.assertEqual(gle, expected_gle)
|
||||
self.assertSequenceEqual(gle, expected_gle)
|
||||
|
||||
|
||||
def make_asset_value_adjustment(**args):
|
||||
|
||||
@@ -180,12 +180,20 @@ class RequestforQuotation(BuyingController):
|
||||
doc_args = self.as_dict()
|
||||
doc_args.update({"supplier": data.get("supplier"), "supplier_name": data.get("supplier_name")})
|
||||
|
||||
# Get Contact Full Name
|
||||
supplier_name = None
|
||||
if data.get("contact"):
|
||||
contact_name = frappe.db.get_value(
|
||||
"Contact", data.get("contact"), ["first_name", "middle_name", "last_name"]
|
||||
)
|
||||
supplier_name = (" ").join(x for x in contact_name if x) # remove any blank values
|
||||
|
||||
args = {
|
||||
"update_password_link": update_password_link,
|
||||
"message": frappe.render_template(self.message_for_supplier, doc_args),
|
||||
"rfq_link": rfq_link,
|
||||
"user_fullname": full_name,
|
||||
"supplier_name": data.get("supplier_name"),
|
||||
"supplier_name": supplier_name or data.get("supplier_name"),
|
||||
"supplier_salutation": self.salutation or "Dear Mx.",
|
||||
}
|
||||
|
||||
|
||||
@@ -68,9 +68,6 @@ frappe.query_reports["Purchase Analytics"] = {
|
||||
}
|
||||
|
||||
],
|
||||
after_datatable_render: function(datatable_obj) {
|
||||
$(datatable_obj.wrapper).find(".dt-row-0").find('input[type=checkbox]').click();
|
||||
},
|
||||
get_datatable_options(options) {
|
||||
return Object.assign(options, {
|
||||
checkboxColumn: true,
|
||||
@@ -130,11 +127,8 @@ frappe.query_reports["Purchase Analytics"] = {
|
||||
labels: raw_data.labels,
|
||||
datasets: new_datasets,
|
||||
};
|
||||
chart_options = {
|
||||
data: new_data,
|
||||
type: "line",
|
||||
};
|
||||
frappe.query_report.render_chart(chart_options);
|
||||
const new_options = Object.assign({}, frappe.query_report.chart_options, {data: new_data});
|
||||
frappe.query_report.render_chart(new_options);
|
||||
|
||||
frappe.query_report.raw_chart_data = new_data;
|
||||
},
|
||||
|
||||
@@ -1472,8 +1472,15 @@ class AccountsController(TransactionBase):
|
||||
self.get("debit_to") if self.doctype == "Sales Invoice" else self.get("credit_to")
|
||||
)
|
||||
party_account_currency = get_account_currency(party_account)
|
||||
allow_multi_currency_invoices_against_single_party_account = frappe.db.get_singles_value(
|
||||
"Accounts Settings", "allow_multi_currency_invoices_against_single_party_account"
|
||||
)
|
||||
|
||||
if not party_gle_currency and (party_account_currency != self.currency):
|
||||
if (
|
||||
not party_gle_currency
|
||||
and (party_account_currency != self.currency)
|
||||
and not allow_multi_currency_invoices_against_single_party_account
|
||||
):
|
||||
frappe.throw(
|
||||
_("Party Account {0} currency ({1}) and document currency ({2}) should be same").format(
|
||||
frappe.bold(party_account), party_account_currency, self.currency
|
||||
|
||||
@@ -7,8 +7,8 @@ from frappe.desk.form import assign_to
|
||||
from frappe.model.document import Document
|
||||
from frappe.utils import add_days, flt, unique
|
||||
|
||||
from erpnext.hr.doctype.employee.employee import get_holiday_list_for_employee
|
||||
from erpnext.hr.doctype.holiday_list.holiday_list import is_holiday
|
||||
from erpnext.setup.doctype.employee.employee import get_holiday_list_for_employee
|
||||
from erpnext.setup.doctype.holiday_list.holiday_list import is_holiday
|
||||
|
||||
|
||||
class EmployeeBoardingController(Document):
|
||||
|
||||
@@ -615,13 +615,13 @@ class SellingController(StockController):
|
||||
stock_items = [d.item_code, d.description, d.warehouse, ""]
|
||||
non_stock_items = [d.item_code, d.description]
|
||||
|
||||
duplicate_items_msg = _("Item {0} entered multiple times.").format(frappe.bold(d.item_code))
|
||||
duplicate_items_msg += "<br><br>"
|
||||
duplicate_items_msg += _("Please enable {} in {} to allow same item in multiple rows").format(
|
||||
frappe.bold("Allow Item to Be Added Multiple Times in a Transaction"),
|
||||
get_link_to_form("Selling Settings", "Selling Settings"),
|
||||
)
|
||||
if frappe.db.get_value("Item", d.item_code, "is_stock_item") == 1:
|
||||
duplicate_items_msg = _("Item {0} entered multiple times.").format(frappe.bold(d.item_code))
|
||||
duplicate_items_msg += "<br><br>"
|
||||
duplicate_items_msg += _("Please enable {} in {} to allow same item in multiple rows").format(
|
||||
frappe.bold("Allow Item to Be Added Multiple Times in a Transaction"),
|
||||
get_link_to_form("Selling Settings", "Selling Settings"),
|
||||
)
|
||||
if stock_items in check_list:
|
||||
frappe.throw(duplicate_items_msg)
|
||||
else:
|
||||
|
||||
@@ -18,6 +18,9 @@ from erpnext.accounts.general_ledger import (
|
||||
from erpnext.accounts.utils import get_fiscal_year
|
||||
from erpnext.controllers.accounts_controller import AccountsController
|
||||
from erpnext.stock import get_warehouse_account_map
|
||||
from erpnext.stock.doctype.inventory_dimension.inventory_dimension import (
|
||||
get_evaluated_inventory_dimension,
|
||||
)
|
||||
from erpnext.stock.stock_ledger import get_items_to_be_repost
|
||||
|
||||
|
||||
@@ -364,8 +367,16 @@ class StockController(AccountsController):
|
||||
)
|
||||
|
||||
sl_dict.update(args)
|
||||
self.update_inventory_dimensions(d, sl_dict)
|
||||
|
||||
return sl_dict
|
||||
|
||||
def update_inventory_dimensions(self, row, sl_dict) -> None:
|
||||
dimensions = get_evaluated_inventory_dimension(row, sl_dict, parent_doc=self)
|
||||
for dimension in dimensions:
|
||||
if dimension and row.get(dimension.source_fieldname):
|
||||
sl_dict[dimension.target_fieldname] = row.get(dimension.source_fieldname)
|
||||
|
||||
def make_sl_entries(self, sl_entries, allow_negative_stock=False, via_landed_cost_voucher=False):
|
||||
from erpnext.stock.stock_ledger import make_sl_entries
|
||||
|
||||
|
||||
@@ -54,7 +54,6 @@ erpnext.LeadController = class LeadController extends frappe.ui.form.Controller
|
||||
frappe.contacts.clear_address_and_contact(this.frm);
|
||||
}
|
||||
|
||||
this.frm.dashboard.links_area.hide();
|
||||
this.show_notes();
|
||||
this.show_activities();
|
||||
}
|
||||
|
||||
@@ -74,7 +74,8 @@
|
||||
"all_activities_html",
|
||||
"notes_tab",
|
||||
"notes_html",
|
||||
"notes"
|
||||
"notes",
|
||||
"dashboard_tab"
|
||||
],
|
||||
"fields": [
|
||||
{
|
||||
@@ -337,9 +338,10 @@
|
||||
},
|
||||
{
|
||||
"fieldname": "no_of_employees",
|
||||
"fieldtype": "Int",
|
||||
"label": "No. of Employees"
|
||||
},
|
||||
"fieldtype": "Select",
|
||||
"label": "No of Employees",
|
||||
"options": "1-10\n11-20\n21-30\n31-100\n11-50\n51-200\n201-500\n101-500\n500-1000\n501-1000\n>1000\n1000+"
|
||||
},
|
||||
{
|
||||
"fieldname": "column_break_22",
|
||||
"fieldtype": "Column Break"
|
||||
@@ -500,13 +502,19 @@
|
||||
"fieldtype": "Link",
|
||||
"label": "Country",
|
||||
"options": "Country"
|
||||
},
|
||||
{
|
||||
"fieldname": "dashboard_tab",
|
||||
"fieldtype": "Tab Break",
|
||||
"label": "Dashboard",
|
||||
"show_dashboard": 1
|
||||
}
|
||||
],
|
||||
"icon": "fa fa-user",
|
||||
"idx": 5,
|
||||
"image_field": "image",
|
||||
"links": [],
|
||||
"modified": "2022-06-27 21:56:17.392756",
|
||||
"modified": "2022-07-22 15:55:03.176094",
|
||||
"modified_by": "Administrator",
|
||||
"module": "CRM",
|
||||
"name": "Lead",
|
||||
|
||||
@@ -84,7 +84,7 @@ frappe.ui.form.on("Opportunity", {
|
||||
erpnext.toggle_naming_series();
|
||||
|
||||
if(!frm.is_new() && doc.status!=="Lost") {
|
||||
if(doc.with_items){
|
||||
if(doc.items){
|
||||
frm.add_custom_button(__('Supplier Quotation'),
|
||||
function() {
|
||||
frm.trigger("make_supplier_quotation")
|
||||
|
||||
@@ -225,16 +225,12 @@
|
||||
"fieldname": "items_section",
|
||||
"fieldtype": "Tab Break",
|
||||
"label": "Items",
|
||||
"oldfieldtype": "Section Break",
|
||||
"options": "fa fa-shopping-cart"
|
||||
},
|
||||
{
|
||||
"fieldname": "items",
|
||||
"fieldtype": "Table",
|
||||
"label": "Items",
|
||||
"mandatory_depends_on": "eval: doc.with_items == 1",
|
||||
"oldfieldname": "enquiry_details",
|
||||
"oldfieldtype": "Table",
|
||||
"options": "Opportunity Item"
|
||||
},
|
||||
{
|
||||
@@ -409,7 +405,6 @@
|
||||
"read_only": 1
|
||||
},
|
||||
{
|
||||
"depends_on": "with_items",
|
||||
"fieldname": "section_break_32",
|
||||
"fieldtype": "Section Break",
|
||||
"hide_border": 1
|
||||
@@ -466,8 +461,9 @@
|
||||
},
|
||||
{
|
||||
"fieldname": "no_of_employees",
|
||||
"fieldtype": "Int",
|
||||
"label": "No of Employees"
|
||||
"fieldtype": "Select",
|
||||
"label": "No of Employees",
|
||||
"options": "1-10\n11-20\n21-30\n31-100\n11-50\n51-200\n201-500\n101-500\n500-1000\n501-1000\n>1000\n1000+"
|
||||
},
|
||||
{
|
||||
"fieldname": "annual_revenue",
|
||||
@@ -626,7 +622,7 @@
|
||||
"icon": "fa fa-info-sign",
|
||||
"idx": 195,
|
||||
"links": [],
|
||||
"modified": "2022-06-27 18:44:32.858696",
|
||||
"modified": "2022-07-22 18:46:32.858696",
|
||||
"modified_by": "Administrator",
|
||||
"module": "CRM",
|
||||
"name": "Opportunity",
|
||||
|
||||
@@ -218,7 +218,7 @@
|
||||
],
|
||||
"index_web_pages_for_search": 1,
|
||||
"links": [],
|
||||
"modified": "2022-06-21 15:10:26.887502",
|
||||
"modified": "2022-06-22 15:10:26.887502",
|
||||
"modified_by": "Administrator",
|
||||
"module": "CRM",
|
||||
"name": "Prospect",
|
||||
|
||||
@@ -201,26 +201,21 @@ class OpportunitySummaryBySalesStage(object):
|
||||
def get_chart_data(self):
|
||||
labels = []
|
||||
datasets = []
|
||||
values = [0] * 8
|
||||
|
||||
for sales_stage in self.sales_stage_list:
|
||||
labels.append(sales_stage)
|
||||
values = [0] * len(self.sales_stage_list)
|
||||
|
||||
options = {"Number": "count", "Amount": "amount"}[self.filters.get("data_based_on")]
|
||||
|
||||
for data in self.query_result:
|
||||
for count in range(len(values)):
|
||||
if data["sales_stage"] == labels[count]:
|
||||
for count in range(len(self.sales_stage_list)):
|
||||
if data["sales_stage"] == self.sales_stage_list[count]:
|
||||
values[count] = values[count] + data[options]
|
||||
|
||||
datasets.append({"name": options, "values": values})
|
||||
self.chart = {"data": {"labels": self.sales_stage_list, "datasets": datasets}, "type": "line"}
|
||||
|
||||
self.chart = {"data": {"labels": labels, "datasets": datasets}, "type": "line"}
|
||||
|
||||
def currency_conversion(self, from_currency, to_currency):
|
||||
def get_exchange_rate(self, from_currency, to_currency):
|
||||
cacheobj = frappe.cache()
|
||||
|
||||
if cacheobj.get(from_currency):
|
||||
if cacheobj and cacheobj.get(from_currency):
|
||||
return flt(str(cacheobj.get(from_currency), "UTF-8"))
|
||||
|
||||
else:
|
||||
@@ -235,7 +230,7 @@ class OpportunitySummaryBySalesStage(object):
|
||||
def convert_to_base_currency(self):
|
||||
default_currency = self.get_default_currency()
|
||||
for data in self.query_result:
|
||||
if data.get("currency") != default_currency:
|
||||
if data.get("currency") and data.get("currency") != default_currency:
|
||||
opportunity_currency = data.get("currency")
|
||||
value = self.currency_conversion(opportunity_currency, default_currency)
|
||||
data["amount"] = data["amount"] * value
|
||||
exchange_rate = self.get_exchange_rate(opportunity_currency, default_currency)
|
||||
data["amount"] = data["amount"] * exchange_rate
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import frappe
|
||||
from frappe.desk.notifications import notify_mentions
|
||||
from frappe.model.document import Document
|
||||
from frappe.utils import cstr, now, today
|
||||
from pypika import functions
|
||||
@@ -204,6 +205,7 @@ class CRMNote(Document):
|
||||
def add_note(self, note):
|
||||
self.append("notes", {"note": note, "added_by": frappe.session.user, "added_on": now()})
|
||||
self.save()
|
||||
notify_mentions(self.doctype, self.name, note)
|
||||
|
||||
@frappe.whitelist()
|
||||
def edit_note(self, note, row_id):
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
"label": "Territory Wise Sales"
|
||||
}
|
||||
],
|
||||
"content": "[{\"type\":\"onboarding\",\"data\":{\"onboarding_name\":\"CRM\",\"col\":12}},{\"type\":\"chart\",\"data\":{\"chart_name\":\"Territory Wise Sales\",\"col\":12}},{\"type\":\"spacer\",\"data\":{\"col\":12}},{\"type\":\"header\",\"data\":{\"text\":\"<span class=\\\"h4\\\"><b>Your Shortcuts</b></span>\",\"col\":12}},{\"type\":\"shortcut\",\"data\":{\"shortcut_name\":\"Lead\",\"col\":3}},{\"type\":\"shortcut\",\"data\":{\"shortcut_name\":\"Opportunity\",\"col\":3}},{\"type\":\"shortcut\",\"data\":{\"shortcut_name\":\"Customer\",\"col\":3}},{\"type\":\"shortcut\",\"data\":{\"shortcut_name\":\"Sales Analytics\",\"col\":3}},{\"type\":\"shortcut\",\"data\":{\"shortcut_name\":\"Dashboard\",\"col\":3}},{\"type\":\"spacer\",\"data\":{\"col\":12}},{\"type\":\"header\",\"data\":{\"text\":\"<span class=\\\"h4\\\"><b>Reports & Masters</b></span>\",\"col\":12}},{\"type\":\"card\",\"data\":{\"card_name\":\"Sales Pipeline\",\"col\":4}},{\"type\":\"card\",\"data\":{\"card_name\":\"Reports\",\"col\":4}},{\"type\":\"card\",\"data\":{\"card_name\":\"Maintenance\",\"col\":4}},{\"type\":\"card\",\"data\":{\"card_name\":\"Campaign\",\"col\":4}},{\"type\":\"card\",\"data\":{\"card_name\":\"Settings\",\"col\":4}}]",
|
||||
"content": "[{\"type\":\"chart\",\"data\":{\"chart_name\":\"Territory Wise Sales\",\"col\":12}},{\"type\":\"spacer\",\"data\":{\"col\":12}},{\"type\":\"header\",\"data\":{\"text\":\"<span class=\\\"h4\\\"><b>Your Shortcuts</b></span>\",\"col\":12}},{\"type\":\"shortcut\",\"data\":{\"shortcut_name\":\"Lead\",\"col\":3}},{\"type\":\"shortcut\",\"data\":{\"shortcut_name\":\"Opportunity\",\"col\":3}},{\"type\":\"shortcut\",\"data\":{\"shortcut_name\":\"Customer\",\"col\":3}},{\"type\":\"shortcut\",\"data\":{\"shortcut_name\":\"Sales Analytics\",\"col\":3}},{\"type\":\"shortcut\",\"data\":{\"shortcut_name\":\"Dashboard\",\"col\":3}},{\"type\":\"spacer\",\"data\":{\"col\":12}},{\"type\":\"header\",\"data\":{\"text\":\"<span class=\\\"h4\\\"><b>Reports & Masters</b></span>\",\"col\":12}},{\"type\":\"card\",\"data\":{\"card_name\":\"Sales Pipeline\",\"col\":4}},{\"type\":\"card\",\"data\":{\"card_name\":\"Reports\",\"col\":4}},{\"type\":\"card\",\"data\":{\"card_name\":\"Campaign\",\"col\":4}},{\"type\":\"card\",\"data\":{\"card_name\":\"Settings\",\"col\":4}},{\"type\":\"card\",\"data\":{\"card_name\":\"Maintenance\",\"col\":4}}]",
|
||||
"creation": "2020-01-23 14:48:30.183272",
|
||||
"docstatus": 0,
|
||||
"doctype": "Workspace",
|
||||
@@ -45,6 +45,17 @@
|
||||
"onboard": 1,
|
||||
"type": "Link"
|
||||
},
|
||||
{
|
||||
"dependencies": "",
|
||||
"hidden": 0,
|
||||
"is_query_report": 0,
|
||||
"label": "Prospect",
|
||||
"link_count": 0,
|
||||
"link_to": "Prospect",
|
||||
"link_type": "DocType",
|
||||
"onboard": 1,
|
||||
"type": "Link"
|
||||
},
|
||||
{
|
||||
"dependencies": "",
|
||||
"hidden": 0,
|
||||
@@ -78,17 +89,6 @@
|
||||
"onboard": 0,
|
||||
"type": "Link"
|
||||
},
|
||||
{
|
||||
"dependencies": "",
|
||||
"hidden": 0,
|
||||
"is_query_report": 0,
|
||||
"label": "Lead Source",
|
||||
"link_count": 0,
|
||||
"link_to": "Lead Source",
|
||||
"link_type": "DocType",
|
||||
"onboard": 0,
|
||||
"type": "Link"
|
||||
},
|
||||
{
|
||||
"dependencies": "",
|
||||
"hidden": 0,
|
||||
@@ -122,6 +122,60 @@
|
||||
"onboard": 0,
|
||||
"type": "Link"
|
||||
},
|
||||
{
|
||||
"dependencies": "",
|
||||
"hidden": 0,
|
||||
"is_query_report": 0,
|
||||
"label": "Lead Source",
|
||||
"link_count": 0,
|
||||
"link_to": "Lead Source",
|
||||
"link_type": "DocType",
|
||||
"onboard": 0,
|
||||
"type": "Link"
|
||||
},
|
||||
{
|
||||
"dependencies": "",
|
||||
"hidden": 0,
|
||||
"is_query_report": 0,
|
||||
"label": "Territory",
|
||||
"link_count": 0,
|
||||
"link_to": "Territory",
|
||||
"link_type": "DocType",
|
||||
"onboard": 1,
|
||||
"type": "Link"
|
||||
},
|
||||
{
|
||||
"dependencies": "",
|
||||
"hidden": 0,
|
||||
"is_query_report": 0,
|
||||
"label": "Customer Group",
|
||||
"link_count": 0,
|
||||
"link_to": "Customer Group",
|
||||
"link_type": "DocType",
|
||||
"onboard": 1,
|
||||
"type": "Link"
|
||||
},
|
||||
{
|
||||
"dependencies": "",
|
||||
"hidden": 0,
|
||||
"is_query_report": 0,
|
||||
"label": "Sales Person",
|
||||
"link_count": 0,
|
||||
"link_to": "Sales Person",
|
||||
"link_type": "DocType",
|
||||
"onboard": 1,
|
||||
"type": "Link"
|
||||
},
|
||||
{
|
||||
"hidden": 0,
|
||||
"is_query_report": 0,
|
||||
"label": "Sales Stage",
|
||||
"link_count": 0,
|
||||
"link_to": "Sales Stage",
|
||||
"link_type": "DocType",
|
||||
"onboard": 0,
|
||||
"type": "Link"
|
||||
},
|
||||
{
|
||||
"hidden": 0,
|
||||
"is_query_report": 0,
|
||||
@@ -227,47 +281,6 @@
|
||||
"onboard": 0,
|
||||
"type": "Link"
|
||||
},
|
||||
{
|
||||
"hidden": 0,
|
||||
"is_query_report": 0,
|
||||
"label": "Maintenance",
|
||||
"link_count": 0,
|
||||
"onboard": 0,
|
||||
"type": "Card Break"
|
||||
},
|
||||
{
|
||||
"dependencies": "",
|
||||
"hidden": 0,
|
||||
"is_query_report": 0,
|
||||
"label": "Maintenance Schedule",
|
||||
"link_count": 0,
|
||||
"link_to": "Maintenance Schedule",
|
||||
"link_type": "DocType",
|
||||
"onboard": 1,
|
||||
"type": "Link"
|
||||
},
|
||||
{
|
||||
"dependencies": "",
|
||||
"hidden": 0,
|
||||
"is_query_report": 0,
|
||||
"label": "Maintenance Visit",
|
||||
"link_count": 0,
|
||||
"link_to": "Maintenance Visit",
|
||||
"link_type": "DocType",
|
||||
"onboard": 0,
|
||||
"type": "Link"
|
||||
},
|
||||
{
|
||||
"dependencies": "",
|
||||
"hidden": 0,
|
||||
"is_query_report": 0,
|
||||
"label": "Warranty Claim",
|
||||
"link_count": 0,
|
||||
"link_to": "Warranty Claim",
|
||||
"link_type": "DocType",
|
||||
"onboard": 0,
|
||||
"type": "Link"
|
||||
},
|
||||
{
|
||||
"hidden": 0,
|
||||
"is_query_report": 0,
|
||||
@@ -309,47 +322,6 @@
|
||||
"onboard": 0,
|
||||
"type": "Link"
|
||||
},
|
||||
{
|
||||
"hidden": 0,
|
||||
"is_query_report": 0,
|
||||
"label": "Settings",
|
||||
"link_count": 0,
|
||||
"onboard": 0,
|
||||
"type": "Card Break"
|
||||
},
|
||||
{
|
||||
"dependencies": "",
|
||||
"hidden": 0,
|
||||
"is_query_report": 0,
|
||||
"label": "Customer Group",
|
||||
"link_count": 0,
|
||||
"link_to": "Customer Group",
|
||||
"link_type": "DocType",
|
||||
"onboard": 1,
|
||||
"type": "Link"
|
||||
},
|
||||
{
|
||||
"dependencies": "",
|
||||
"hidden": 0,
|
||||
"is_query_report": 0,
|
||||
"label": "Territory",
|
||||
"link_count": 0,
|
||||
"link_to": "Territory",
|
||||
"link_type": "DocType",
|
||||
"onboard": 1,
|
||||
"type": "Link"
|
||||
},
|
||||
{
|
||||
"dependencies": "",
|
||||
"hidden": 0,
|
||||
"is_query_report": 0,
|
||||
"label": "Sales Person",
|
||||
"link_count": 0,
|
||||
"link_to": "Sales Person",
|
||||
"link_type": "DocType",
|
||||
"onboard": 1,
|
||||
"type": "Link"
|
||||
},
|
||||
{
|
||||
"dependencies": "",
|
||||
"hidden": 0,
|
||||
@@ -376,9 +348,27 @@
|
||||
"dependencies": "",
|
||||
"hidden": 0,
|
||||
"is_query_report": 0,
|
||||
"label": "SMS Settings",
|
||||
"label": "Email Group",
|
||||
"link_count": 0,
|
||||
"link_to": "SMS Settings",
|
||||
"link_to": "Email Group",
|
||||
"link_type": "DocType",
|
||||
"onboard": 0,
|
||||
"type": "Link"
|
||||
},
|
||||
{
|
||||
"hidden": 0,
|
||||
"is_query_report": 0,
|
||||
"label": "Settings",
|
||||
"link_count": 0,
|
||||
"onboard": 0,
|
||||
"type": "Card Break"
|
||||
},
|
||||
{
|
||||
"hidden": 0,
|
||||
"is_query_report": 0,
|
||||
"label": "CRM Settings",
|
||||
"link_count": 0,
|
||||
"link_to": "CRM Settings",
|
||||
"link_type": "DocType",
|
||||
"onboard": 0,
|
||||
"type": "Link"
|
||||
@@ -387,9 +377,9 @@
|
||||
"dependencies": "",
|
||||
"hidden": 0,
|
||||
"is_query_report": 0,
|
||||
"label": "Email Group",
|
||||
"label": "SMS Settings",
|
||||
"link_count": 0,
|
||||
"link_to": "Email Group",
|
||||
"link_to": "SMS Settings",
|
||||
"link_type": "DocType",
|
||||
"onboard": 0,
|
||||
"type": "Link"
|
||||
@@ -415,15 +405,57 @@
|
||||
"link_type": "DocType",
|
||||
"onboard": 0,
|
||||
"type": "Link"
|
||||
},
|
||||
{
|
||||
"hidden": 0,
|
||||
"is_query_report": 0,
|
||||
"label": "Maintenance",
|
||||
"link_count": 0,
|
||||
"onboard": 0,
|
||||
"type": "Card Break"
|
||||
},
|
||||
{
|
||||
"dependencies": "",
|
||||
"hidden": 0,
|
||||
"is_query_report": 0,
|
||||
"label": "Maintenance Schedule",
|
||||
"link_count": 0,
|
||||
"link_to": "Maintenance Schedule",
|
||||
"link_type": "DocType",
|
||||
"onboard": 1,
|
||||
"type": "Link"
|
||||
},
|
||||
{
|
||||
"dependencies": "",
|
||||
"hidden": 0,
|
||||
"is_query_report": 0,
|
||||
"label": "Maintenance Visit",
|
||||
"link_count": 0,
|
||||
"link_to": "Maintenance Visit",
|
||||
"link_type": "DocType",
|
||||
"onboard": 0,
|
||||
"type": "Link"
|
||||
},
|
||||
{
|
||||
"dependencies": "",
|
||||
"hidden": 0,
|
||||
"is_query_report": 0,
|
||||
"label": "Warranty Claim",
|
||||
"link_count": 0,
|
||||
"link_to": "Warranty Claim",
|
||||
"link_type": "DocType",
|
||||
"onboard": 0,
|
||||
"type": "Link"
|
||||
}
|
||||
],
|
||||
"modified": "2022-01-13 17:53:17.509844",
|
||||
"modified": "2022-07-22 15:03:30.755417",
|
||||
"modified_by": "Administrator",
|
||||
"module": "CRM",
|
||||
"name": "CRM",
|
||||
"owner": "Administrator",
|
||||
"parent_page": "",
|
||||
"public": 1,
|
||||
"quick_lists": [],
|
||||
"restrict_to_domain": "",
|
||||
"roles": [],
|
||||
"sequence_id": 7.0,
|
||||
|
||||
@@ -48,7 +48,7 @@
|
||||
"read_only": 1
|
||||
},
|
||||
{
|
||||
"fetch_from": "website_item.image",
|
||||
"fetch_from": "website_item.website_image",
|
||||
"fieldname": "website_item_image",
|
||||
"fieldtype": "Attach",
|
||||
"label": "Website Item Image",
|
||||
@@ -75,7 +75,7 @@
|
||||
"index_web_pages_for_search": 1,
|
||||
"istable": 1,
|
||||
"links": [],
|
||||
"modified": "2021-07-13 21:02:19.031652",
|
||||
"modified": "2022-06-28 16:44:24.718728",
|
||||
"modified_by": "Administrator",
|
||||
"module": "E-commerce",
|
||||
"name": "Recommended Items",
|
||||
@@ -83,5 +83,6 @@
|
||||
"permissions": [],
|
||||
"sort_field": "modified",
|
||||
"sort_order": "DESC",
|
||||
"states": [],
|
||||
"track_changes": 1
|
||||
}
|
||||
@@ -30,10 +30,6 @@ frappe.ui.form.on('Website Item', {
|
||||
}, __("View"));
|
||||
},
|
||||
|
||||
image: () => {
|
||||
refresh_field("image_view");
|
||||
},
|
||||
|
||||
copy_from_item_group: (frm) => {
|
||||
return frm.call({
|
||||
doc: frm.doc,
|
||||
|
||||
@@ -22,7 +22,6 @@
|
||||
"column_break_11",
|
||||
"description",
|
||||
"brand",
|
||||
"image",
|
||||
"display_section",
|
||||
"website_image",
|
||||
"website_image_alt",
|
||||
@@ -113,8 +112,11 @@
|
||||
{
|
||||
"description": "Item Image (if not slideshow)",
|
||||
"fieldname": "website_image",
|
||||
"fieldtype": "Attach",
|
||||
"label": "Website Image"
|
||||
"fieldtype": "Attach Image",
|
||||
"hidden": 1,
|
||||
"in_preview": 1,
|
||||
"label": "Website Image",
|
||||
"print_hide": 1
|
||||
},
|
||||
{
|
||||
"description": "Image Alternative Text",
|
||||
@@ -188,14 +190,6 @@
|
||||
"options": "Item Group",
|
||||
"read_only": 1
|
||||
},
|
||||
{
|
||||
"fieldname": "image",
|
||||
"fieldtype": "Attach Image",
|
||||
"hidden": 1,
|
||||
"in_preview": 1,
|
||||
"label": "Image",
|
||||
"print_hide": 1
|
||||
},
|
||||
{
|
||||
"default": "1",
|
||||
"fieldname": "published",
|
||||
@@ -348,13 +342,14 @@
|
||||
}
|
||||
],
|
||||
"has_web_view": 1,
|
||||
"image_field": "image",
|
||||
"image_field": "website_image",
|
||||
"index_web_pages_for_search": 1,
|
||||
"links": [],
|
||||
"modified": "2021-09-02 13:08:41.942726",
|
||||
"modified": "2022-06-28 17:10:30.613251",
|
||||
"modified_by": "Administrator",
|
||||
"module": "E-commerce",
|
||||
"name": "Website Item",
|
||||
"naming_rule": "Expression (old style)",
|
||||
"owner": "Administrator",
|
||||
"permissions": [
|
||||
{
|
||||
@@ -410,6 +405,7 @@
|
||||
"show_name_in_global_search": 1,
|
||||
"sort_field": "modified",
|
||||
"sort_order": "DESC",
|
||||
"states": [],
|
||||
"title_field": "web_item_name",
|
||||
"track_changes": 1
|
||||
}
|
||||
@@ -1,8 +1,12 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# Copyright (c) 2021, Frappe Technologies Pvt. Ltd. and contributors
|
||||
# Copyright (c) 2022, Frappe Technologies Pvt. Ltd. and contributors
|
||||
# For license information, please see license.txt
|
||||
|
||||
import json
|
||||
from typing import TYPE_CHECKING, List, Union
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from erpnext.stock.doctype.item.item import Item
|
||||
|
||||
import frappe
|
||||
from frappe import _
|
||||
@@ -114,11 +118,6 @@ class WebsiteItem(WebsiteGenerator):
|
||||
return
|
||||
|
||||
"""Validate if the website image is a public file"""
|
||||
auto_set_website_image = False
|
||||
if not self.website_image and self.image:
|
||||
auto_set_website_image = True
|
||||
self.website_image = self.image
|
||||
|
||||
if not self.website_image:
|
||||
return
|
||||
|
||||
@@ -135,18 +134,16 @@ class WebsiteItem(WebsiteGenerator):
|
||||
file_doc = file_doc[0]
|
||||
|
||||
if not file_doc:
|
||||
if not auto_set_website_image:
|
||||
frappe.msgprint(
|
||||
_("Website Image {0} attached to Item {1} cannot be found").format(
|
||||
self.website_image, self.name
|
||||
)
|
||||
frappe.msgprint(
|
||||
_("Website Image {0} attached to Item {1} cannot be found").format(
|
||||
self.website_image, self.name
|
||||
)
|
||||
)
|
||||
|
||||
self.website_image = None
|
||||
|
||||
elif file_doc.is_private:
|
||||
if not auto_set_website_image:
|
||||
frappe.msgprint(_("Website Image should be a public file or website URL"))
|
||||
frappe.msgprint(_("Website Image should be a public file or website URL"))
|
||||
|
||||
self.website_image = None
|
||||
|
||||
@@ -157,9 +154,8 @@ class WebsiteItem(WebsiteGenerator):
|
||||
|
||||
import requests.exceptions
|
||||
|
||||
if not self.is_new() and self.website_image != frappe.db.get_value(
|
||||
self.doctype, self.name, "website_image"
|
||||
):
|
||||
db_website_image = frappe.db.get_value(self.doctype, self.name, "website_image")
|
||||
if not self.is_new() and self.website_image != db_website_image:
|
||||
self.thumbnail = None
|
||||
|
||||
if self.website_image and not self.thumbnail:
|
||||
@@ -431,7 +427,9 @@ def check_if_user_is_customer(user=None):
|
||||
|
||||
|
||||
@frappe.whitelist()
|
||||
def make_website_item(doc, save=True):
|
||||
def make_website_item(doc: "Item", save: bool = True) -> Union["WebsiteItem", List[str]]:
|
||||
"Make Website Item from Item. Used via Form UI or patch."
|
||||
|
||||
if not doc:
|
||||
return
|
||||
|
||||
@@ -451,7 +449,6 @@ def make_website_item(doc, save=True):
|
||||
"item_group",
|
||||
"stock_uom",
|
||||
"brand",
|
||||
"image",
|
||||
"has_variants",
|
||||
"variant_of",
|
||||
"description",
|
||||
@@ -459,6 +456,10 @@ def make_website_item(doc, save=True):
|
||||
for field in fields_to_map:
|
||||
website_item.update({field: doc.get(field)})
|
||||
|
||||
# Needed for publishing/mapping via Form UI only
|
||||
if not frappe.flags.in_migrate and (doc.get("image") and not website_item.website_image):
|
||||
website_item.website_image = doc.get("image")
|
||||
|
||||
if not save:
|
||||
return website_item
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
frappe.listview_settings['Website Item'] = {
|
||||
add_fields: ["item_name", "web_item_name", "published", "image", "has_variants", "variant_of"],
|
||||
add_fields: ["item_name", "web_item_name", "published", "website_image", "has_variants", "variant_of"],
|
||||
filters: [["published", "=", "1"]],
|
||||
|
||||
get_indicator: function(doc) {
|
||||
|
||||
@@ -20,7 +20,15 @@ def add_to_wishlist(item_code):
|
||||
web_item_data = frappe.db.get_value(
|
||||
"Website Item",
|
||||
{"item_code": item_code},
|
||||
["image", "website_warehouse", "name", "web_item_name", "item_name", "item_group", "route"],
|
||||
[
|
||||
"website_image",
|
||||
"website_warehouse",
|
||||
"name",
|
||||
"web_item_name",
|
||||
"item_name",
|
||||
"item_group",
|
||||
"route",
|
||||
],
|
||||
as_dict=1,
|
||||
)
|
||||
|
||||
@@ -30,7 +38,7 @@ def add_to_wishlist(item_code):
|
||||
"item_group": web_item_data.get("item_group"),
|
||||
"website_item": web_item_data.get("name"),
|
||||
"web_item_name": web_item_data.get("web_item_name"),
|
||||
"image": web_item_data.get("image"),
|
||||
"image": web_item_data.get("website_image"),
|
||||
"warehouse": web_item_data.get("website_warehouse"),
|
||||
"route": web_item_data.get("route"),
|
||||
}
|
||||
|
||||
@@ -35,7 +35,6 @@ class ProductQuery:
|
||||
"variant_of",
|
||||
"has_variants",
|
||||
"item_group",
|
||||
"image",
|
||||
"web_long_description",
|
||||
"short_description",
|
||||
"route",
|
||||
|
||||
@@ -35,7 +35,7 @@ erpnext.ProductGrid = class {
|
||||
}
|
||||
|
||||
get_image_html(item, title) {
|
||||
let image = item.website_image || item.image;
|
||||
let image = item.website_image;
|
||||
|
||||
if (image) {
|
||||
return `
|
||||
|
||||
@@ -35,7 +35,7 @@ erpnext.ProductList = class {
|
||||
}
|
||||
|
||||
get_image_html(item, title, settings) {
|
||||
let image = item.website_image || item.image;
|
||||
let image = item.website_image;
|
||||
let wishlist_enabled = !item.has_variants && settings.enable_wishlist;
|
||||
let image_html = ``;
|
||||
|
||||
|
||||
@@ -7,9 +7,10 @@ from urllib.parse import urlencode
|
||||
import frappe
|
||||
import gocardless_pro
|
||||
from frappe import _
|
||||
from frappe.integrations.utils import create_payment_gateway, create_request_log
|
||||
from frappe.integrations.utils import create_request_log
|
||||
from frappe.model.document import Document
|
||||
from frappe.utils import call_hook_method, cint, flt, get_url
|
||||
from payments.utils import create_payment_gateway
|
||||
|
||||
|
||||
class GoCardlessSettings(Document):
|
||||
|
||||
@@ -6,9 +6,10 @@ from json import dumps, loads
|
||||
|
||||
import frappe
|
||||
from frappe import _
|
||||
from frappe.integrations.utils import create_payment_gateway, create_request_log
|
||||
from frappe.integrations.utils import create_request_log
|
||||
from frappe.model.document import Document
|
||||
from frappe.utils import call_hook_method, fmt_money, get_request_site_address
|
||||
from payments.utils import create_payment_gateway
|
||||
|
||||
from erpnext.erpnext_integrations.doctype.mpesa_settings.mpesa_connector import MpesaConnector
|
||||
from erpnext.erpnext_integrations.doctype.mpesa_settings.mpesa_custom_fields import (
|
||||
|
||||
@@ -10,6 +10,7 @@ app_email = "info@erpnext.com"
|
||||
app_license = "GNU General Public License (v3)"
|
||||
source_link = "https://github.com/frappe/erpnext"
|
||||
app_logo_url = "/assets/erpnext/images/erpnext-logo.svg"
|
||||
required_apps = ["payments"]
|
||||
|
||||
|
||||
develop_version = "14.x.x-develop"
|
||||
@@ -80,13 +81,14 @@ calendars = [
|
||||
"Holiday List",
|
||||
]
|
||||
|
||||
website_generators = ["Item Group", "Website Item", "BOM", "Sales Partner", "Job Opening"]
|
||||
website_generators = ["Item Group", "Website Item", "BOM", "Sales Partner"]
|
||||
|
||||
website_context = {
|
||||
"favicon": "/assets/erpnext/images/erpnext-favicon.svg",
|
||||
"splash_image": "/assets/erpnext/images/erpnext-logo.svg",
|
||||
}
|
||||
|
||||
# nosemgrep
|
||||
website_route_rules = [
|
||||
{"from_route": "/orders", "to_route": "Sales Order"},
|
||||
{
|
||||
@@ -163,7 +165,6 @@ website_route_rules = [
|
||||
"to_route": "addresses",
|
||||
"defaults": {"doctype": "Address", "parents": [{"label": _("Addresses"), "route": "addresses"}]},
|
||||
},
|
||||
{"from_route": "/jobs", "to_route": "Job Opening"},
|
||||
{"from_route": "/boms", "to_route": "BOM"},
|
||||
{"from_route": "/timesheets", "to_route": "Timesheet"},
|
||||
{"from_route": "/material-requests", "to_route": "Material Request"},
|
||||
@@ -256,7 +257,9 @@ sounds = [
|
||||
{"name": "call-disconnect", "src": "/assets/erpnext/sounds/call-disconnect.mp3", "volume": 0.2},
|
||||
]
|
||||
|
||||
has_upload_permission = {"Employee": "erpnext.hr.doctype.employee.employee.has_upload_permission"}
|
||||
has_upload_permission = {
|
||||
"Employee": "erpnext.setup.doctype.employee.employee.has_upload_permission"
|
||||
}
|
||||
|
||||
has_website_permission = {
|
||||
"Sales Order": "erpnext.controllers.website_list_for_contact.has_website_permission",
|
||||
@@ -289,9 +292,9 @@ doc_events = {
|
||||
},
|
||||
"User": {
|
||||
"after_insert": "frappe.contacts.doctype.contact.contact.update_contact",
|
||||
"validate": "erpnext.hr.doctype.employee.employee.validate_employee_role",
|
||||
"validate": "erpnext.setup.doctype.employee.employee.validate_employee_role",
|
||||
"on_update": [
|
||||
"erpnext.hr.doctype.employee.employee.update_user_permissions",
|
||||
"erpnext.setup.doctype.employee.employee.update_user_permissions",
|
||||
"erpnext.portal.utils.set_default_role",
|
||||
],
|
||||
},
|
||||
@@ -366,8 +369,6 @@ auto_cancel_exempted_doctypes = [
|
||||
"Payment Entry",
|
||||
]
|
||||
|
||||
after_migrate = ["erpnext.setup.install.update_select_perm_after_install"]
|
||||
|
||||
scheduler_events = {
|
||||
"cron": {
|
||||
"0/5 * * * *": [
|
||||
@@ -387,16 +388,13 @@ scheduler_events = {
|
||||
},
|
||||
"all": [
|
||||
"erpnext.projects.doctype.project.project.project_status_update_reminder",
|
||||
"erpnext.hr.doctype.interview.interview.send_interview_reminder",
|
||||
"erpnext.crm.doctype.social_media_post.social_media_post.process_scheduled_social_media_posts",
|
||||
],
|
||||
"hourly": [
|
||||
"erpnext.hr.doctype.daily_work_summary_group.daily_work_summary_group.trigger_emails",
|
||||
"erpnext.accounts.doctype.subscription.subscription.process_all",
|
||||
"erpnext.erpnext_integrations.doctype.plaid_settings.plaid_settings.automatic_synchronization",
|
||||
"erpnext.projects.doctype.project.project.hourly_reminder",
|
||||
"erpnext.projects.doctype.project.project.collect_project_status",
|
||||
"erpnext.hr.doctype.shift_type.shift_type.process_auto_attendance_for_all_shifts",
|
||||
],
|
||||
"hourly_long": [
|
||||
"erpnext.stock.doctype.repost_item_valuation.repost_item_valuation.repost_entries",
|
||||
@@ -407,11 +405,8 @@ scheduler_events = {
|
||||
"erpnext.crm.doctype.opportunity.opportunity.auto_close_opportunity",
|
||||
"erpnext.controllers.accounts_controller.update_invoice_status",
|
||||
"erpnext.accounts.doctype.fiscal_year.fiscal_year.auto_create_fiscal_year",
|
||||
"erpnext.hr.doctype.employee.employee_reminders.send_work_anniversary_reminders",
|
||||
"erpnext.hr.doctype.employee.employee_reminders.send_birthday_reminders",
|
||||
"erpnext.projects.doctype.task.task.set_tasks_as_overdue",
|
||||
"erpnext.assets.doctype.asset.depreciation.post_depreciation_entries",
|
||||
"erpnext.hr.doctype.daily_work_summary_group.daily_work_summary_group.send_summary",
|
||||
"erpnext.stock.doctype.serial_no.serial_no.update_maintenance_status",
|
||||
"erpnext.buying.doctype.supplier_scorecard.supplier_scorecard.refresh_scorecards",
|
||||
"erpnext.setup.doctype.company.company.cache_companies_monthly_sales_history",
|
||||
@@ -427,20 +422,14 @@ scheduler_events = {
|
||||
"erpnext.selling.doctype.quotation.quotation.set_expired_status",
|
||||
"erpnext.buying.doctype.supplier_quotation.supplier_quotation.set_expired_status",
|
||||
"erpnext.accounts.doctype.process_statement_of_accounts.process_statement_of_accounts.send_auto_email",
|
||||
"erpnext.hr.doctype.interview.interview.send_daily_feedback_reminder",
|
||||
],
|
||||
"daily_long": [
|
||||
"erpnext.setup.doctype.email_digest.email_digest.send",
|
||||
"erpnext.manufacturing.doctype.bom_update_tool.bom_update_tool.auto_update_latest_price_in_all_boms",
|
||||
"erpnext.hr.doctype.leave_ledger_entry.leave_ledger_entry.process_expired_allocation",
|
||||
"erpnext.hr.utils.generate_leave_encashment",
|
||||
"erpnext.hr.utils.allocate_earned_leaves",
|
||||
"erpnext.loan_management.doctype.process_loan_security_shortfall.process_loan_security_shortfall.create_process_loan_security_shortfall",
|
||||
"erpnext.loan_management.doctype.process_loan_interest_accrual.process_loan_interest_accrual.process_loan_interest_accrual_for_term_loans",
|
||||
"erpnext.crm.utils.open_leads_opportunities_based_on_todays_event",
|
||||
],
|
||||
"weekly": ["erpnext.hr.doctype.employee.employee_reminders.send_reminders_in_advance_weekly"],
|
||||
"monthly": ["erpnext.hr.doctype.employee.employee_reminders.send_reminders_in_advance_monthly"],
|
||||
"monthly_long": [
|
||||
"erpnext.accounts.deferred_revenue.process_deferred_accounting",
|
||||
"erpnext.loan_management.doctype.process_loan_interest_accrual.process_loan_interest_accrual.process_loan_interest_accrual_for_demand_loans",
|
||||
@@ -472,6 +461,28 @@ payment_gateway_enabled = "erpnext.accounts.utils.create_payment_gateway_account
|
||||
|
||||
communication_doctypes = ["Customer", "Supplier"]
|
||||
|
||||
advance_payment_doctypes = ["Sales Order", "Purchase Order"]
|
||||
|
||||
invoice_doctypes = ["Sales Invoice", "Purchase Invoice"]
|
||||
|
||||
period_closing_doctypes = [
|
||||
"Sales Invoice",
|
||||
"Purchase Invoice",
|
||||
"Journal Entry",
|
||||
"Bank Clearance",
|
||||
"Asset",
|
||||
"Stock Entry",
|
||||
]
|
||||
|
||||
bank_reconciliation_doctypes = [
|
||||
"Payment Entry",
|
||||
"Journal Entry",
|
||||
"Purchase Invoice",
|
||||
"Sales Invoice",
|
||||
"Loan Repayment",
|
||||
"Loan Disbursement",
|
||||
]
|
||||
|
||||
accounting_dimension_doctypes = [
|
||||
"GL Entry",
|
||||
"Payment Ledger Entry",
|
||||
@@ -479,12 +490,8 @@ accounting_dimension_doctypes = [
|
||||
"Purchase Invoice",
|
||||
"Payment Entry",
|
||||
"Asset",
|
||||
"Expense Claim",
|
||||
"Expense Claim Detail",
|
||||
"Expense Taxes and Charges",
|
||||
"Stock Entry",
|
||||
"Budget",
|
||||
"Payroll Entry",
|
||||
"Delivery Note",
|
||||
"Sales Invoice Item",
|
||||
"Purchase Invoice Item",
|
||||
@@ -502,7 +509,6 @@ accounting_dimension_doctypes = [
|
||||
"Asset Value Adjustment",
|
||||
"Loyalty Program",
|
||||
"Stock Reconciliation",
|
||||
"Travel Request",
|
||||
"POS Profile",
|
||||
"Opening Invoice Creation Tool",
|
||||
"Opening Invoice Creation Tool Item",
|
||||
@@ -515,14 +521,15 @@ accounting_dimension_doctypes = [
|
||||
"Sales Order",
|
||||
]
|
||||
|
||||
# get matching queries for Bank Reconciliation
|
||||
get_matching_queries = (
|
||||
"erpnext.accounts.doctype.bank_reconciliation_tool.bank_reconciliation_tool.get_matching_queries"
|
||||
)
|
||||
|
||||
regional_overrides = {
|
||||
"France": {
|
||||
"erpnext.tests.test_regional.test_method": "erpnext.regional.france.utils.test_method"
|
||||
},
|
||||
"India": {
|
||||
"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",
|
||||
},
|
||||
"United Arab Emirates": {
|
||||
"erpnext.controllers.taxes_and_totals.update_itemised_tax_data": "erpnext.regional.united_arab_emirates.utils.update_itemised_tax_data",
|
||||
"erpnext.accounts.doctype.purchase_invoice.purchase_invoice.make_regional_gl_entries": "erpnext.regional.united_arab_emirates.utils.make_regional_gl_entries",
|
||||
@@ -570,9 +577,6 @@ global_search_doctypes = {
|
||||
{"doctype": "Material Request", "index": 16},
|
||||
{"doctype": "Delivery Trip", "index": 17},
|
||||
{"doctype": "Pick List", "index": 18},
|
||||
{"doctype": "Salary Slip", "index": 19},
|
||||
{"doctype": "Leave Application", "index": 20},
|
||||
{"doctype": "Expense Claim", "index": 21},
|
||||
{"doctype": "Payment Entry", "index": 22},
|
||||
{"doctype": "Lead", "index": 23},
|
||||
{"doctype": "Opportunity", "index": 24},
|
||||
@@ -588,13 +592,7 @@ global_search_doctypes = {
|
||||
{"doctype": "Batch", "index": 34},
|
||||
{"doctype": "Branch", "index": 35},
|
||||
{"doctype": "Department", "index": 36},
|
||||
{"doctype": "Employee Grade", "index": 37},
|
||||
{"doctype": "Designation", "index": 38},
|
||||
{"doctype": "Job Opening", "index": 39},
|
||||
{"doctype": "Job Applicant", "index": 40},
|
||||
{"doctype": "Job Offer", "index": 41},
|
||||
{"doctype": "Salary Structure Assignment", "index": 42},
|
||||
{"doctype": "Appraisal", "index": 43},
|
||||
{"doctype": "Loan", "index": 44},
|
||||
{"doctype": "Maintenance Schedule", "index": 45},
|
||||
{"doctype": "Maintenance Visit", "index": 46},
|
||||
|
||||
@@ -1,6 +0,0 @@
|
||||
Key features:
|
||||
|
||||
- Leave and Attendance
|
||||
- Payroll
|
||||
- Appraisal
|
||||
- Expense Claim
|
||||
@@ -1,27 +0,0 @@
|
||||
{
|
||||
"chart_name": "Attendance Count",
|
||||
"chart_type": "Report",
|
||||
"creation": "2020-07-22 11:56:32.730068",
|
||||
"custom_options": "{\n\t\t\"type\": \"line\",\n\t\t\"axisOptions\": {\n\t\t\t\"shortenYAxisNumbers\": 1\n\t\t},\n\t\t\"tooltipOptions\": {}\n\t}",
|
||||
"docstatus": 0,
|
||||
"doctype": "Dashboard Chart",
|
||||
"dynamic_filters_json": "{\"month\":\"frappe.datetime.str_to_obj(frappe.datetime.get_today()).getMonth() + 1\",\"year\":\"frappe.datetime.str_to_obj(frappe.datetime.get_today()).getFullYear();\",\"company\":\"frappe.defaults.get_user_default(\\\"Company\\\")\"}",
|
||||
"filters_json": "{}",
|
||||
"group_by_type": "Count",
|
||||
"idx": 0,
|
||||
"is_public": 1,
|
||||
"is_standard": 1,
|
||||
"modified": "2020-07-22 14:32:40.334424",
|
||||
"modified_by": "Administrator",
|
||||
"module": "HR",
|
||||
"name": "Attendance Count",
|
||||
"number_of_groups": 0,
|
||||
"owner": "Administrator",
|
||||
"report_name": "Monthly Attendance Sheet",
|
||||
"time_interval": "Yearly",
|
||||
"timeseries": 0,
|
||||
"timespan": "Last Year",
|
||||
"type": "Line",
|
||||
"use_report_chart": 1,
|
||||
"y_axis": []
|
||||
}
|
||||
@@ -1,29 +0,0 @@
|
||||
{
|
||||
"chart_name": "Department Wise Employee Count",
|
||||
"chart_type": "Group By",
|
||||
"creation": "2020-07-22 11:56:32.760730",
|
||||
"custom_options": "",
|
||||
"docstatus": 0,
|
||||
"doctype": "Dashboard Chart",
|
||||
"document_type": "Employee",
|
||||
"dynamic_filters_json": "[[\"Employee\",\"company\",\"=\",\"frappe.defaults.get_user_default(\\\"Company\\\")\"]]",
|
||||
"filters_json": "[[\"Employee\",\"status\",\"=\",\"Active\",false]]",
|
||||
"group_by_based_on": "department",
|
||||
"group_by_type": "Count",
|
||||
"idx": 0,
|
||||
"is_public": 1,
|
||||
"is_standard": 1,
|
||||
"last_synced_on": "2020-07-22 14:27:40.574194",
|
||||
"modified": "2020-07-22 14:33:38.036794",
|
||||
"modified_by": "Administrator",
|
||||
"module": "HR",
|
||||
"name": "Department Wise Employee Count",
|
||||
"number_of_groups": 0,
|
||||
"owner": "Administrator",
|
||||
"time_interval": "Yearly",
|
||||
"timeseries": 0,
|
||||
"timespan": "Last Year",
|
||||
"type": "Donut",
|
||||
"use_report_chart": 0,
|
||||
"y_axis": []
|
||||
}
|
||||
@@ -1,29 +0,0 @@
|
||||
{
|
||||
"aggregate_function_based_on": "planned_vacancies",
|
||||
"chart_name": "Department Wise Openings",
|
||||
"chart_type": "Group By",
|
||||
"creation": "2020-07-22 11:56:32.849775",
|
||||
"custom_options": "",
|
||||
"docstatus": 0,
|
||||
"doctype": "Dashboard Chart",
|
||||
"document_type": "Job Opening",
|
||||
"filters_json": "[]",
|
||||
"group_by_based_on": "department",
|
||||
"group_by_type": "Sum",
|
||||
"idx": 0,
|
||||
"is_public": 1,
|
||||
"is_standard": 1,
|
||||
"last_synced_on": "2020-07-22 14:33:44.834801",
|
||||
"modified": "2020-07-22 14:34:45.273591",
|
||||
"modified_by": "Administrator",
|
||||
"module": "HR",
|
||||
"name": "Department Wise Openings",
|
||||
"number_of_groups": 0,
|
||||
"owner": "Administrator",
|
||||
"time_interval": "Monthly",
|
||||
"timeseries": 0,
|
||||
"timespan": "Last Year",
|
||||
"type": "Bar",
|
||||
"use_report_chart": 0,
|
||||
"y_axis": []
|
||||
}
|
||||
@@ -1,29 +0,0 @@
|
||||
{
|
||||
"chart_name": "Designation Wise Employee Count",
|
||||
"chart_type": "Group By",
|
||||
"creation": "2020-07-22 11:56:32.790337",
|
||||
"custom_options": "",
|
||||
"docstatus": 0,
|
||||
"doctype": "Dashboard Chart",
|
||||
"document_type": "Employee",
|
||||
"dynamic_filters_json": "[[\"Employee\",\"company\",\"=\",\"frappe.defaults.get_user_default(\\\"Company\\\")\"]]",
|
||||
"filters_json": "[[\"Employee\",\"status\",\"=\",\"Active\",false]]",
|
||||
"group_by_based_on": "designation",
|
||||
"group_by_type": "Count",
|
||||
"idx": 0,
|
||||
"is_public": 1,
|
||||
"is_standard": 1,
|
||||
"last_synced_on": "2020-07-22 14:27:40.602783",
|
||||
"modified": "2020-07-22 14:31:49.665555",
|
||||
"modified_by": "Administrator",
|
||||
"module": "HR",
|
||||
"name": "Designation Wise Employee Count",
|
||||
"number_of_groups": 0,
|
||||
"owner": "Administrator",
|
||||
"time_interval": "Yearly",
|
||||
"timeseries": 0,
|
||||
"timespan": "Last Year",
|
||||
"type": "Donut",
|
||||
"use_report_chart": 0,
|
||||
"y_axis": []
|
||||
}
|
||||
@@ -1,30 +0,0 @@
|
||||
{
|
||||
"aggregate_function_based_on": "planned_vacancies",
|
||||
"chart_name": "Designation Wise Openings",
|
||||
"chart_type": "Group By",
|
||||
"creation": "2020-07-22 11:56:32.820217",
|
||||
"custom_options": "",
|
||||
"docstatus": 0,
|
||||
"doctype": "Dashboard Chart",
|
||||
"document_type": "Job Opening",
|
||||
"dynamic_filters_json": "",
|
||||
"filters_json": "[]",
|
||||
"group_by_based_on": "designation",
|
||||
"group_by_type": "Sum",
|
||||
"idx": 0,
|
||||
"is_public": 1,
|
||||
"is_standard": 1,
|
||||
"last_synced_on": "2020-07-22 14:33:44.806626",
|
||||
"modified": "2020-07-22 14:34:32.711881",
|
||||
"modified_by": "Administrator",
|
||||
"module": "HR",
|
||||
"name": "Designation Wise Openings",
|
||||
"number_of_groups": 0,
|
||||
"owner": "Administrator",
|
||||
"time_interval": "Monthly",
|
||||
"timeseries": 0,
|
||||
"timespan": "Last Year",
|
||||
"type": "Bar",
|
||||
"use_report_chart": 0,
|
||||
"y_axis": []
|
||||
}
|
||||
@@ -1,29 +0,0 @@
|
||||
{
|
||||
"chart_name": "Gender Diversity Ratio",
|
||||
"chart_type": "Group By",
|
||||
"creation": "2020-07-22 11:56:32.667291",
|
||||
"custom_options": "",
|
||||
"docstatus": 0,
|
||||
"doctype": "Dashboard Chart",
|
||||
"document_type": "Employee",
|
||||
"dynamic_filters_json": "[[\"Employee\",\"company\",\"=\",\"frappe.defaults.get_user_default(\\\"Company\\\")\"]]",
|
||||
"filters_json": "[[\"Employee\",\"status\",\"=\",\"Active\",false]]",
|
||||
"group_by_based_on": "gender",
|
||||
"group_by_type": "Count",
|
||||
"idx": 0,
|
||||
"is_public": 1,
|
||||
"is_standard": 1,
|
||||
"last_synced_on": "2020-07-22 14:27:40.143783",
|
||||
"modified": "2020-07-22 14:32:50.962459",
|
||||
"modified_by": "Administrator",
|
||||
"module": "HR",
|
||||
"name": "Gender Diversity Ratio",
|
||||
"number_of_groups": 0,
|
||||
"owner": "Administrator",
|
||||
"time_interval": "Yearly",
|
||||
"timeseries": 0,
|
||||
"timespan": "Last Year",
|
||||
"type": "Pie",
|
||||
"use_report_chart": 0,
|
||||
"y_axis": []
|
||||
}
|
||||
@@ -1,29 +0,0 @@
|
||||
{
|
||||
"chart_name": "Job Application Status",
|
||||
"chart_type": "Group By",
|
||||
"creation": "2020-07-22 11:56:32.699696",
|
||||
"custom_options": "",
|
||||
"docstatus": 0,
|
||||
"doctype": "Dashboard Chart",
|
||||
"document_type": "Job Applicant",
|
||||
"dynamic_filters_json": "",
|
||||
"filters_json": "[[\"Job Applicant\",\"creation\",\"Timespan\",\"last month\",false]]",
|
||||
"group_by_based_on": "status",
|
||||
"group_by_type": "Count",
|
||||
"idx": 0,
|
||||
"is_public": 1,
|
||||
"is_standard": 1,
|
||||
"last_synced_on": "2020-07-28 16:19:12.109979",
|
||||
"modified": "2020-07-28 16:19:45.279490",
|
||||
"modified_by": "Administrator",
|
||||
"module": "HR",
|
||||
"name": "Job Application Status",
|
||||
"number_of_groups": 0,
|
||||
"owner": "Administrator",
|
||||
"time_interval": "Yearly",
|
||||
"timeseries": 0,
|
||||
"timespan": "Last Year",
|
||||
"type": "Pie",
|
||||
"use_report_chart": 0,
|
||||
"y_axis": []
|
||||
}
|
||||
@@ -1,30 +0,0 @@
|
||||
// Copyright (c) 2019, Frappe Technologies Pvt. Ltd. and contributors
|
||||
// For license information, please see license.txt
|
||||
|
||||
frappe.ui.form.on('Appointment Letter', {
|
||||
appointment_letter_template: function(frm){
|
||||
if (frm.doc.appointment_letter_template){
|
||||
frappe.call({
|
||||
method: 'erpnext.hr.doctype.appointment_letter.appointment_letter.get_appointment_letter_details',
|
||||
args : {
|
||||
template : frm.doc.appointment_letter_template
|
||||
},
|
||||
callback: function(r){
|
||||
if(r.message){
|
||||
let message_body = r.message;
|
||||
frm.set_value("introduction", message_body[0].introduction);
|
||||
frm.set_value("closing_notes", message_body[0].closing_notes);
|
||||
frm.doc.terms = []
|
||||
for (var i in message_body[1].description){
|
||||
frm.add_child("terms");
|
||||
frm.fields_dict.terms.get_value()[i].title = message_body[1].description[i].title;
|
||||
frm.fields_dict.terms.get_value()[i].description = message_body[1].description[i].description;
|
||||
}
|
||||
frm.refresh();
|
||||
}
|
||||
}
|
||||
|
||||
});
|
||||
}
|
||||
},
|
||||
});
|
||||
@@ -1,128 +0,0 @@
|
||||
{
|
||||
"actions": [],
|
||||
"autoname": "HR-APP-LETTER-.#####",
|
||||
"creation": "2019-12-26 12:35:49.574828",
|
||||
"default_print_format": "Standard Appointment Letter",
|
||||
"doctype": "DocType",
|
||||
"editable_grid": 1,
|
||||
"engine": "InnoDB",
|
||||
"field_order": [
|
||||
"job_applicant",
|
||||
"applicant_name",
|
||||
"column_break_3",
|
||||
"company",
|
||||
"appointment_date",
|
||||
"appointment_letter_template",
|
||||
"body_section",
|
||||
"introduction",
|
||||
"terms",
|
||||
"closing_notes"
|
||||
],
|
||||
"fields": [
|
||||
{
|
||||
"fetch_from": "job_applicant.applicant_name",
|
||||
"fieldname": "applicant_name",
|
||||
"fieldtype": "Data",
|
||||
"in_global_search": 1,
|
||||
"in_list_view": 1,
|
||||
"label": "Applicant Name",
|
||||
"read_only": 1,
|
||||
"reqd": 1
|
||||
},
|
||||
{
|
||||
"fieldname": "appointment_date",
|
||||
"fieldtype": "Date",
|
||||
"label": "Appointment Date",
|
||||
"reqd": 1
|
||||
},
|
||||
{
|
||||
"fieldname": "appointment_letter_template",
|
||||
"fieldtype": "Link",
|
||||
"label": "Appointment Letter Template",
|
||||
"options": "Appointment Letter Template",
|
||||
"reqd": 1
|
||||
},
|
||||
{
|
||||
"fetch_from": "appointment_letter_template.introduction",
|
||||
"fieldname": "introduction",
|
||||
"fieldtype": "Long Text",
|
||||
"label": "Introduction",
|
||||
"reqd": 1
|
||||
},
|
||||
{
|
||||
"fieldname": "body_section",
|
||||
"fieldtype": "Section Break",
|
||||
"label": "Body"
|
||||
},
|
||||
{
|
||||
"fieldname": "column_break_3",
|
||||
"fieldtype": "Column Break"
|
||||
},
|
||||
{
|
||||
"fieldname": "job_applicant",
|
||||
"fieldtype": "Link",
|
||||
"label": "Job Applicant",
|
||||
"options": "Job Applicant",
|
||||
"reqd": 1
|
||||
},
|
||||
{
|
||||
"fieldname": "company",
|
||||
"fieldtype": "Link",
|
||||
"label": "Company",
|
||||
"options": "Company",
|
||||
"reqd": 1
|
||||
},
|
||||
{
|
||||
"fieldname": "closing_notes",
|
||||
"fieldtype": "Text",
|
||||
"label": "Closing Notes"
|
||||
},
|
||||
{
|
||||
"fieldname": "terms",
|
||||
"fieldtype": "Table",
|
||||
"label": "Terms",
|
||||
"options": "Appointment Letter content",
|
||||
"reqd": 1
|
||||
}
|
||||
],
|
||||
"links": [],
|
||||
"modified": "2022-01-18 19:27:35.649424",
|
||||
"modified_by": "Administrator",
|
||||
"module": "HR",
|
||||
"name": "Appointment Letter",
|
||||
"name_case": "Title Case",
|
||||
"naming_rule": "Expression (old style)",
|
||||
"owner": "Administrator",
|
||||
"permissions": [
|
||||
{
|
||||
"create": 1,
|
||||
"delete": 1,
|
||||
"email": 1,
|
||||
"export": 1,
|
||||
"print": 1,
|
||||
"read": 1,
|
||||
"report": 1,
|
||||
"role": "System Manager",
|
||||
"share": 1,
|
||||
"write": 1
|
||||
},
|
||||
{
|
||||
"create": 1,
|
||||
"delete": 1,
|
||||
"email": 1,
|
||||
"export": 1,
|
||||
"print": 1,
|
||||
"read": 1,
|
||||
"report": 1,
|
||||
"role": "HR Manager",
|
||||
"share": 1,
|
||||
"write": 1
|
||||
}
|
||||
],
|
||||
"search_fields": "applicant_name, company",
|
||||
"sort_field": "modified",
|
||||
"sort_order": "DESC",
|
||||
"states": [],
|
||||
"title_field": "applicant_name",
|
||||
"track_changes": 1
|
||||
}
|
||||
@@ -1,29 +0,0 @@
|
||||
# Copyright (c) 2019, Frappe Technologies Pvt. Ltd. and contributors
|
||||
# For license information, please see license.txt
|
||||
|
||||
|
||||
import frappe
|
||||
from frappe.model.document import Document
|
||||
|
||||
|
||||
class AppointmentLetter(Document):
|
||||
pass
|
||||
|
||||
|
||||
@frappe.whitelist()
|
||||
def get_appointment_letter_details(template):
|
||||
body = []
|
||||
intro = frappe.get_list(
|
||||
"Appointment Letter Template",
|
||||
fields=["introduction", "closing_notes"],
|
||||
filters={"name": template},
|
||||
)[0]
|
||||
content = frappe.get_all(
|
||||
"Appointment Letter content",
|
||||
fields=["title", "description"],
|
||||
filters={"parent": template},
|
||||
order_by="idx",
|
||||
)
|
||||
body.append(intro)
|
||||
body.append({"description": content})
|
||||
return body
|
||||
@@ -1,9 +0,0 @@
|
||||
# Copyright (c) 2019, Frappe Technologies Pvt. Ltd. and Contributors
|
||||
# See license.txt
|
||||
|
||||
# import frappe
|
||||
import unittest
|
||||
|
||||
|
||||
class TestAppointmentLetter(unittest.TestCase):
|
||||
pass
|
||||
@@ -1,39 +0,0 @@
|
||||
{
|
||||
"actions": [],
|
||||
"creation": "2019-12-26 12:22:16.575767",
|
||||
"doctype": "DocType",
|
||||
"editable_grid": 1,
|
||||
"engine": "InnoDB",
|
||||
"field_order": [
|
||||
"title",
|
||||
"description"
|
||||
],
|
||||
"fields": [
|
||||
{
|
||||
"fieldname": "title",
|
||||
"fieldtype": "Data",
|
||||
"in_list_view": 1,
|
||||
"label": "Title",
|
||||
"reqd": 1
|
||||
},
|
||||
{
|
||||
"fieldname": "description",
|
||||
"fieldtype": "Long Text",
|
||||
"in_list_view": 1,
|
||||
"label": "Description",
|
||||
"reqd": 1
|
||||
}
|
||||
],
|
||||
"istable": 1,
|
||||
"links": [],
|
||||
"modified": "2019-12-26 12:24:09.824084",
|
||||
"modified_by": "Administrator",
|
||||
"module": "HR",
|
||||
"name": "Appointment Letter content",
|
||||
"owner": "Administrator",
|
||||
"permissions": [],
|
||||
"quick_entry": 1,
|
||||
"sort_field": "modified",
|
||||
"sort_order": "DESC",
|
||||
"track_changes": 1
|
||||
}
|
||||
@@ -1,10 +0,0 @@
|
||||
# Copyright (c) 2019, Frappe Technologies Pvt. Ltd. and contributors
|
||||
# For license information, please see license.txt
|
||||
|
||||
|
||||
# import frappe
|
||||
from frappe.model.document import Document
|
||||
|
||||
|
||||
class AppointmentLettercontent(Document):
|
||||
pass
|
||||
@@ -1,8 +0,0 @@
|
||||
// Copyright (c) 2019, Frappe Technologies Pvt. Ltd. and contributors
|
||||
// For license information, please see license.txt
|
||||
|
||||
frappe.ui.form.on('Appointment Letter Template', {
|
||||
// refresh: function(frm) {
|
||||
|
||||
// }
|
||||
});
|
||||
@@ -1,81 +0,0 @@
|
||||
{
|
||||
"actions": [],
|
||||
"autoname": "field:template_name",
|
||||
"creation": "2019-12-26 12:20:14.219578",
|
||||
"doctype": "DocType",
|
||||
"editable_grid": 1,
|
||||
"engine": "InnoDB",
|
||||
"field_order": [
|
||||
"template_name",
|
||||
"introduction",
|
||||
"terms",
|
||||
"closing_notes"
|
||||
],
|
||||
"fields": [
|
||||
{
|
||||
"fieldname": "introduction",
|
||||
"fieldtype": "Long Text",
|
||||
"in_list_view": 1,
|
||||
"label": "Introduction",
|
||||
"reqd": 1
|
||||
},
|
||||
{
|
||||
"fieldname": "closing_notes",
|
||||
"fieldtype": "Text",
|
||||
"label": "Closing Notes"
|
||||
},
|
||||
{
|
||||
"fieldname": "terms",
|
||||
"fieldtype": "Table",
|
||||
"label": "Terms",
|
||||
"options": "Appointment Letter content",
|
||||
"reqd": 1
|
||||
},
|
||||
{
|
||||
"fieldname": "template_name",
|
||||
"fieldtype": "Data",
|
||||
"label": "Template Name",
|
||||
"reqd": 1,
|
||||
"unique": 1
|
||||
}
|
||||
],
|
||||
"links": [],
|
||||
"modified": "2022-01-18 19:25:14.614616",
|
||||
"modified_by": "Administrator",
|
||||
"module": "HR",
|
||||
"name": "Appointment Letter Template",
|
||||
"naming_rule": "By fieldname",
|
||||
"owner": "Administrator",
|
||||
"permissions": [
|
||||
{
|
||||
"create": 1,
|
||||
"delete": 1,
|
||||
"email": 1,
|
||||
"export": 1,
|
||||
"print": 1,
|
||||
"read": 1,
|
||||
"report": 1,
|
||||
"role": "System Manager",
|
||||
"share": 1,
|
||||
"write": 1
|
||||
},
|
||||
{
|
||||
"create": 1,
|
||||
"delete": 1,
|
||||
"email": 1,
|
||||
"export": 1,
|
||||
"print": 1,
|
||||
"read": 1,
|
||||
"report": 1,
|
||||
"role": "HR Manager",
|
||||
"share": 1,
|
||||
"write": 1
|
||||
}
|
||||
],
|
||||
"search_fields": "template_name",
|
||||
"sort_field": "modified",
|
||||
"sort_order": "DESC",
|
||||
"states": [],
|
||||
"title_field": "template_name",
|
||||
"track_changes": 1
|
||||
}
|
||||
@@ -1,10 +0,0 @@
|
||||
# Copyright (c) 2019, Frappe Technologies Pvt. Ltd. and contributors
|
||||
# For license information, please see license.txt
|
||||
|
||||
|
||||
# import frappe
|
||||
from frappe.model.document import Document
|
||||
|
||||
|
||||
class AppointmentLetterTemplate(Document):
|
||||
pass
|
||||
@@ -1,9 +0,0 @@
|
||||
# Copyright (c) 2019, Frappe Technologies Pvt. Ltd. and Contributors
|
||||
# See license.txt
|
||||
|
||||
# import frappe
|
||||
import unittest
|
||||
|
||||
|
||||
class TestAppointmentLetterTemplate(unittest.TestCase):
|
||||
pass
|
||||
@@ -1 +0,0 @@
|
||||
Performance of an Employee in a Time Period against given goals.
|
||||
@@ -1,79 +0,0 @@
|
||||
// Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors
|
||||
// License: GNU General Public License v3. See license.txt
|
||||
|
||||
frappe.ui.form.on('Appraisal', {
|
||||
setup: function(frm) {
|
||||
frm.add_fetch('employee', 'company', 'company');
|
||||
frm.add_fetch('employee', 'employee_name', 'employee_name');
|
||||
frm.fields_dict.employee.get_query = function(doc,cdt,cdn) {
|
||||
return{ query: "erpnext.controllers.queries.employee_query" }
|
||||
};
|
||||
},
|
||||
|
||||
onload: function(frm) {
|
||||
if(!frm.doc.status) {
|
||||
frm.set_value('status', 'Draft');
|
||||
}
|
||||
},
|
||||
|
||||
kra_template: function(frm) {
|
||||
frm.doc.goals = [];
|
||||
erpnext.utils.map_current_doc({
|
||||
method: "erpnext.hr.doctype.appraisal.appraisal.fetch_appraisal_template",
|
||||
source_name: frm.doc.kra_template,
|
||||
frm: frm
|
||||
});
|
||||
},
|
||||
|
||||
calculate_total: function(frm) {
|
||||
let goals = frm.doc.goals || [];
|
||||
let total = 0;
|
||||
|
||||
if (goals == []) {
|
||||
frm.set_value('total_score', 0);
|
||||
return;
|
||||
}
|
||||
for (let i = 0; i<goals.length; i++) {
|
||||
total = flt(total)+flt(goals[i].score_earned)
|
||||
}
|
||||
if (!isNaN(total)) {
|
||||
frm.set_value('total_score', total);
|
||||
frm.refresh_field('calculate_total');
|
||||
}
|
||||
},
|
||||
|
||||
set_score_earned: function(frm) {
|
||||
let goals = frm.doc.goals || [];
|
||||
for (let i = 0; i<goals.length; i++) {
|
||||
var d = locals[goals[i].doctype][goals[i].name];
|
||||
if (d.score && d.per_weightage) {
|
||||
d.score_earned = flt(d.per_weightage*d.score, precision("score_earned", d))/100;
|
||||
}
|
||||
else {
|
||||
d.score_earned = 0;
|
||||
}
|
||||
refresh_field('score_earned', d.name, 'goals');
|
||||
}
|
||||
frm.trigger('calculate_total');
|
||||
}
|
||||
});
|
||||
|
||||
frappe.ui.form.on('Appraisal Goal', {
|
||||
score: function(frm, cdt, cdn) {
|
||||
var d = locals[cdt][cdn];
|
||||
if (flt(d.score) > 5) {
|
||||
frappe.msgprint(__("Score must be less than or equal to 5"));
|
||||
d.score = 0;
|
||||
refresh_field('score', d.name, 'goals');
|
||||
}
|
||||
else {
|
||||
frm.trigger('set_score_earned');
|
||||
}
|
||||
},
|
||||
per_weightage: function(frm) {
|
||||
frm.trigger('set_score_earned');
|
||||
},
|
||||
goals_remove: function(frm) {
|
||||
frm.trigger('set_score_earned');
|
||||
}
|
||||
});
|
||||
@@ -1,254 +0,0 @@
|
||||
{
|
||||
"actions": [],
|
||||
"autoname": "naming_series:",
|
||||
"creation": "2013-01-10 16:34:12",
|
||||
"doctype": "DocType",
|
||||
"document_type": "Setup",
|
||||
"engine": "InnoDB",
|
||||
"field_order": [
|
||||
"employee_details",
|
||||
"naming_series",
|
||||
"kra_template",
|
||||
"employee",
|
||||
"employee_name",
|
||||
"column_break0",
|
||||
"status",
|
||||
"start_date",
|
||||
"end_date",
|
||||
"department",
|
||||
"section_break0",
|
||||
"goals",
|
||||
"total_score",
|
||||
"section_break1",
|
||||
"remarks",
|
||||
"other_details",
|
||||
"company",
|
||||
"column_break_17",
|
||||
"amended_from"
|
||||
],
|
||||
"fields": [
|
||||
{
|
||||
"fieldname": "employee_details",
|
||||
"fieldtype": "Section Break",
|
||||
"oldfieldtype": "Section Break"
|
||||
},
|
||||
{
|
||||
"fieldname": "naming_series",
|
||||
"fieldtype": "Select",
|
||||
"label": "Series",
|
||||
"no_copy": 1,
|
||||
"options": "HR-APR-.YY.-.MM.",
|
||||
"print_hide": 1,
|
||||
"reqd": 1,
|
||||
"set_only_once": 1
|
||||
},
|
||||
{
|
||||
"fieldname": "kra_template",
|
||||
"fieldtype": "Link",
|
||||
"in_standard_filter": 1,
|
||||
"label": "Appraisal Template",
|
||||
"oldfieldname": "kra_template",
|
||||
"oldfieldtype": "Link",
|
||||
"options": "Appraisal Template",
|
||||
"reqd": 1
|
||||
},
|
||||
{
|
||||
"depends_on": "kra_template",
|
||||
"fieldname": "employee",
|
||||
"fieldtype": "Link",
|
||||
"in_global_search": 1,
|
||||
"in_standard_filter": 1,
|
||||
"label": "For Employee",
|
||||
"oldfieldname": "employee",
|
||||
"oldfieldtype": "Link",
|
||||
"options": "Employee",
|
||||
"reqd": 1,
|
||||
"search_index": 1
|
||||
},
|
||||
{
|
||||
"depends_on": "kra_template",
|
||||
"fieldname": "employee_name",
|
||||
"fieldtype": "Data",
|
||||
"in_global_search": 1,
|
||||
"label": "For Employee Name",
|
||||
"oldfieldname": "employee_name",
|
||||
"oldfieldtype": "Data",
|
||||
"read_only": 1
|
||||
},
|
||||
{
|
||||
"depends_on": "kra_template",
|
||||
"fieldname": "column_break0",
|
||||
"fieldtype": "Column Break",
|
||||
"oldfieldtype": "Column Break",
|
||||
"width": "50%"
|
||||
},
|
||||
{
|
||||
"default": "Draft",
|
||||
"depends_on": "kra_template",
|
||||
"fieldname": "status",
|
||||
"fieldtype": "Select",
|
||||
"in_standard_filter": 1,
|
||||
"label": "Status",
|
||||
"no_copy": 1,
|
||||
"oldfieldname": "status",
|
||||
"oldfieldtype": "Select",
|
||||
"options": "\nDraft\nSubmitted\nCompleted\nCancelled",
|
||||
"read_only": 1,
|
||||
"reqd": 1,
|
||||
"search_index": 1
|
||||
},
|
||||
{
|
||||
"depends_on": "kra_template",
|
||||
"fieldname": "start_date",
|
||||
"fieldtype": "Date",
|
||||
"in_list_view": 1,
|
||||
"label": "Start Date",
|
||||
"oldfieldname": "start_date",
|
||||
"oldfieldtype": "Date",
|
||||
"reqd": 1
|
||||
},
|
||||
{
|
||||
"depends_on": "kra_template",
|
||||
"fieldname": "end_date",
|
||||
"fieldtype": "Date",
|
||||
"label": "End Date",
|
||||
"oldfieldname": "end_date",
|
||||
"oldfieldtype": "Date",
|
||||
"reqd": 1
|
||||
},
|
||||
{
|
||||
"fetch_from": "employee.department",
|
||||
"fieldname": "department",
|
||||
"fieldtype": "Link",
|
||||
"label": "Department",
|
||||
"options": "Department",
|
||||
"read_only": 1
|
||||
},
|
||||
{
|
||||
"depends_on": "kra_template",
|
||||
"fieldname": "section_break0",
|
||||
"fieldtype": "Section Break",
|
||||
"label": "Goals",
|
||||
"oldfieldtype": "Section Break",
|
||||
"options": "Simple"
|
||||
},
|
||||
{
|
||||
"fieldname": "goals",
|
||||
"fieldtype": "Table",
|
||||
"label": "Goals",
|
||||
"oldfieldname": "appraisal_details",
|
||||
"oldfieldtype": "Table",
|
||||
"options": "Appraisal Goal"
|
||||
},
|
||||
{
|
||||
"fieldname": "total_score",
|
||||
"fieldtype": "Float",
|
||||
"in_list_view": 1,
|
||||
"label": "Total Score (Out of 5)",
|
||||
"no_copy": 1,
|
||||
"oldfieldname": "total_score",
|
||||
"oldfieldtype": "Currency",
|
||||
"read_only": 1
|
||||
},
|
||||
{
|
||||
"depends_on": "kra_template",
|
||||
"fieldname": "section_break1",
|
||||
"fieldtype": "Section Break"
|
||||
},
|
||||
{
|
||||
"description": "Any other remarks, noteworthy effort that should go in the records.",
|
||||
"fieldname": "remarks",
|
||||
"fieldtype": "Text",
|
||||
"label": "Remarks"
|
||||
},
|
||||
{
|
||||
"depends_on": "kra_template",
|
||||
"fieldname": "other_details",
|
||||
"fieldtype": "Section Break"
|
||||
},
|
||||
{
|
||||
"fieldname": "company",
|
||||
"fieldtype": "Link",
|
||||
"label": "Company",
|
||||
"oldfieldname": "company",
|
||||
"oldfieldtype": "Link",
|
||||
"options": "Company",
|
||||
"remember_last_selected_value": 1,
|
||||
"reqd": 1
|
||||
},
|
||||
{
|
||||
"fieldname": "column_break_17",
|
||||
"fieldtype": "Column Break"
|
||||
},
|
||||
{
|
||||
"fieldname": "amended_from",
|
||||
"fieldtype": "Link",
|
||||
"hidden": 1,
|
||||
"ignore_user_permissions": 1,
|
||||
"label": "Amended From",
|
||||
"no_copy": 1,
|
||||
"oldfieldname": "amended_from",
|
||||
"oldfieldtype": "Data",
|
||||
"options": "Appraisal",
|
||||
"print_hide": 1,
|
||||
"read_only": 1,
|
||||
"report_hide": 1,
|
||||
"width": "150px"
|
||||
}
|
||||
],
|
||||
"icon": "fa fa-thumbs-up",
|
||||
"idx": 1,
|
||||
"index_web_pages_for_search": 1,
|
||||
"is_submittable": 1,
|
||||
"links": [],
|
||||
"modified": "2020-10-03 21:48:33.297065",
|
||||
"modified_by": "Administrator",
|
||||
"module": "HR",
|
||||
"name": "Appraisal",
|
||||
"owner": "Administrator",
|
||||
"permissions": [
|
||||
{
|
||||
"create": 1,
|
||||
"email": 1,
|
||||
"print": 1,
|
||||
"read": 1,
|
||||
"report": 1,
|
||||
"role": "Employee",
|
||||
"share": 1,
|
||||
"write": 1
|
||||
},
|
||||
{
|
||||
"amend": 1,
|
||||
"cancel": 1,
|
||||
"create": 1,
|
||||
"delete": 1,
|
||||
"email": 1,
|
||||
"print": 1,
|
||||
"read": 1,
|
||||
"report": 1,
|
||||
"role": "System Manager",
|
||||
"share": 1,
|
||||
"submit": 1,
|
||||
"write": 1
|
||||
},
|
||||
{
|
||||
"amend": 1,
|
||||
"cancel": 1,
|
||||
"create": 1,
|
||||
"delete": 1,
|
||||
"email": 1,
|
||||
"print": 1,
|
||||
"read": 1,
|
||||
"report": 1,
|
||||
"role": "HR User",
|
||||
"share": 1,
|
||||
"submit": 1,
|
||||
"write": 1
|
||||
}
|
||||
],
|
||||
"search_fields": "status, employee, employee_name",
|
||||
"sort_field": "modified",
|
||||
"sort_order": "DESC",
|
||||
"timeline_field": "employee",
|
||||
"title_field": "employee_name"
|
||||
}
|
||||
@@ -1,94 +0,0 @@
|
||||
# Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors
|
||||
# License: GNU General Public License v3. See license.txt
|
||||
|
||||
|
||||
import frappe
|
||||
from frappe import _
|
||||
from frappe.model.document import Document
|
||||
from frappe.model.mapper import get_mapped_doc
|
||||
from frappe.utils import flt, getdate
|
||||
|
||||
from erpnext.hr.utils import set_employee_name, validate_active_employee
|
||||
|
||||
|
||||
class Appraisal(Document):
|
||||
def validate(self):
|
||||
if not self.status:
|
||||
self.status = "Draft"
|
||||
|
||||
if not self.goals:
|
||||
frappe.throw(_("Goals cannot be empty"))
|
||||
|
||||
validate_active_employee(self.employee)
|
||||
set_employee_name(self)
|
||||
self.validate_dates()
|
||||
self.validate_existing_appraisal()
|
||||
self.calculate_total()
|
||||
|
||||
def get_employee_name(self):
|
||||
self.employee_name = frappe.db.get_value("Employee", self.employee, "employee_name")
|
||||
return self.employee_name
|
||||
|
||||
def validate_dates(self):
|
||||
if getdate(self.start_date) > getdate(self.end_date):
|
||||
frappe.throw(_("End Date can not be less than Start Date"))
|
||||
|
||||
def validate_existing_appraisal(self):
|
||||
chk = frappe.db.sql(
|
||||
"""select name from `tabAppraisal` where employee=%s
|
||||
and (status='Submitted' or status='Completed')
|
||||
and ((start_date>=%s and start_date<=%s)
|
||||
or (end_date>=%s and end_date<=%s))""",
|
||||
(self.employee, self.start_date, self.end_date, self.start_date, self.end_date),
|
||||
)
|
||||
if chk:
|
||||
frappe.throw(
|
||||
_("Appraisal {0} created for Employee {1} in the given date range").format(
|
||||
chk[0][0], self.employee_name
|
||||
)
|
||||
)
|
||||
|
||||
def calculate_total(self):
|
||||
total, total_w = 0, 0
|
||||
for d in self.get("goals"):
|
||||
if d.score:
|
||||
d.score_earned = flt(d.score) * flt(d.per_weightage) / 100
|
||||
total = total + d.score_earned
|
||||
total_w += flt(d.per_weightage)
|
||||
|
||||
if int(total_w) != 100:
|
||||
frappe.throw(
|
||||
_("Total weightage assigned should be 100%.<br>It is {0}").format(str(total_w) + "%")
|
||||
)
|
||||
|
||||
if (
|
||||
frappe.db.get_value("Employee", self.employee, "user_id") != frappe.session.user and total == 0
|
||||
):
|
||||
frappe.throw(_("Total cannot be zero"))
|
||||
|
||||
self.total_score = total
|
||||
|
||||
def on_submit(self):
|
||||
frappe.db.set(self, "status", "Submitted")
|
||||
|
||||
def on_cancel(self):
|
||||
frappe.db.set(self, "status", "Cancelled")
|
||||
|
||||
|
||||
@frappe.whitelist()
|
||||
def fetch_appraisal_template(source_name, target_doc=None):
|
||||
target_doc = get_mapped_doc(
|
||||
"Appraisal Template",
|
||||
source_name,
|
||||
{
|
||||
"Appraisal Template": {
|
||||
"doctype": "Appraisal",
|
||||
},
|
||||
"Appraisal Template Goal": {
|
||||
"doctype": "Appraisal Goal",
|
||||
},
|
||||
},
|
||||
target_doc,
|
||||
)
|
||||
|
||||
return target_doc
|
||||
@@ -1,10 +0,0 @@
|
||||
# Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors and Contributors
|
||||
# See license.txt
|
||||
|
||||
import unittest
|
||||
|
||||
# test_records = frappe.get_test_records('Appraisal')
|
||||
|
||||
|
||||
class TestAppraisal(unittest.TestCase):
|
||||
pass
|
||||
@@ -1 +0,0 @@
|
||||
Goal for the parent Appraisal.
|
||||
@@ -1,220 +0,0 @@
|
||||
{
|
||||
"allow_copy": 0,
|
||||
"allow_import": 0,
|
||||
"allow_rename": 0,
|
||||
"autoname": "hash",
|
||||
"beta": 0,
|
||||
"creation": "2013-02-22 01:27:44",
|
||||
"custom": 0,
|
||||
"docstatus": 0,
|
||||
"doctype": "DocType",
|
||||
"editable_grid": 1,
|
||||
"fields": [
|
||||
{
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"description": "Key Responsibility Area",
|
||||
"fieldname": "kra",
|
||||
"fieldtype": "Small Text",
|
||||
"hidden": 0,
|
||||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_list_view": 1,
|
||||
"label": "Goal",
|
||||
"length": 0,
|
||||
"no_copy": 0,
|
||||
"oldfieldname": "kra",
|
||||
"oldfieldtype": "Small Text",
|
||||
"permlevel": 0,
|
||||
"print_hide": 0,
|
||||
"print_hide_if_no_value": 0,
|
||||
"print_width": "240px",
|
||||
"read_only": 0,
|
||||
"report_hide": 0,
|
||||
"reqd": 1,
|
||||
"search_index": 0,
|
||||
"set_only_once": 0,
|
||||
"unique": 0,
|
||||
"width": "240px"
|
||||
},
|
||||
{
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"fieldname": "section_break_2",
|
||||
"fieldtype": "Section Break",
|
||||
"hidden": 0,
|
||||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_list_view": 0,
|
||||
"length": 0,
|
||||
"no_copy": 0,
|
||||
"permlevel": 0,
|
||||
"precision": "",
|
||||
"print_hide": 0,
|
||||
"print_hide_if_no_value": 0,
|
||||
"read_only": 0,
|
||||
"report_hide": 0,
|
||||
"reqd": 0,
|
||||
"search_index": 0,
|
||||
"set_only_once": 0,
|
||||
"unique": 0
|
||||
},
|
||||
{
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"fieldname": "per_weightage",
|
||||
"fieldtype": "Float",
|
||||
"hidden": 0,
|
||||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_list_view": 1,
|
||||
"label": "Weightage (%)",
|
||||
"length": 0,
|
||||
"no_copy": 0,
|
||||
"oldfieldname": "per_weightage",
|
||||
"oldfieldtype": "Currency",
|
||||
"permlevel": 0,
|
||||
"print_hide": 0,
|
||||
"print_hide_if_no_value": 0,
|
||||
"print_width": "70px",
|
||||
"read_only": 0,
|
||||
"report_hide": 0,
|
||||
"reqd": 1,
|
||||
"search_index": 0,
|
||||
"set_only_once": 0,
|
||||
"unique": 0,
|
||||
"width": "70px"
|
||||
},
|
||||
{
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"fieldname": "column_break_4",
|
||||
"fieldtype": "Column Break",
|
||||
"hidden": 0,
|
||||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_list_view": 0,
|
||||
"length": 0,
|
||||
"no_copy": 0,
|
||||
"permlevel": 0,
|
||||
"precision": "",
|
||||
"print_hide": 0,
|
||||
"print_hide_if_no_value": 0,
|
||||
"read_only": 0,
|
||||
"report_hide": 0,
|
||||
"reqd": 0,
|
||||
"search_index": 0,
|
||||
"set_only_once": 0,
|
||||
"unique": 0
|
||||
},
|
||||
{
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"fieldname": "score",
|
||||
"fieldtype": "Float",
|
||||
"hidden": 0,
|
||||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_list_view": 1,
|
||||
"label": "Score (0-5)",
|
||||
"length": 0,
|
||||
"no_copy": 1,
|
||||
"oldfieldname": "score",
|
||||
"oldfieldtype": "Select",
|
||||
"options": "",
|
||||
"permlevel": 0,
|
||||
"print_hide": 0,
|
||||
"print_hide_if_no_value": 0,
|
||||
"print_width": "70px",
|
||||
"read_only": 0,
|
||||
"report_hide": 0,
|
||||
"reqd": 0,
|
||||
"search_index": 0,
|
||||
"set_only_once": 0,
|
||||
"unique": 0,
|
||||
"width": "70px"
|
||||
},
|
||||
{
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"fieldname": "section_break_6",
|
||||
"fieldtype": "Section Break",
|
||||
"hidden": 0,
|
||||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_list_view": 0,
|
||||
"length": 0,
|
||||
"no_copy": 0,
|
||||
"permlevel": 0,
|
||||
"precision": "",
|
||||
"print_hide": 0,
|
||||
"print_hide_if_no_value": 0,
|
||||
"read_only": 0,
|
||||
"report_hide": 0,
|
||||
"reqd": 0,
|
||||
"search_index": 0,
|
||||
"set_only_once": 0,
|
||||
"unique": 0
|
||||
},
|
||||
{
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"fieldname": "score_earned",
|
||||
"fieldtype": "Float",
|
||||
"hidden": 0,
|
||||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_list_view": 1,
|
||||
"label": "Score Earned",
|
||||
"length": 0,
|
||||
"no_copy": 1,
|
||||
"oldfieldname": "score_earned",
|
||||
"oldfieldtype": "Currency",
|
||||
"permlevel": 0,
|
||||
"print_hide": 0,
|
||||
"print_hide_if_no_value": 0,
|
||||
"print_width": "70px",
|
||||
"read_only": 1,
|
||||
"report_hide": 0,
|
||||
"reqd": 0,
|
||||
"search_index": 0,
|
||||
"set_only_once": 0,
|
||||
"unique": 0,
|
||||
"width": "70px"
|
||||
}
|
||||
],
|
||||
"hide_heading": 0,
|
||||
"hide_toolbar": 0,
|
||||
"idx": 1,
|
||||
"image_view": 0,
|
||||
"in_create": 0,
|
||||
|
||||
"is_submittable": 0,
|
||||
"issingle": 0,
|
||||
"istable": 1,
|
||||
"max_attachments": 0,
|
||||
"modified": "2020-09-18 17:26:09.703215",
|
||||
"modified_by": "Administrator",
|
||||
"module": "HR",
|
||||
"name": "Appraisal Goal",
|
||||
"owner": "Administrator",
|
||||
"permissions": [],
|
||||
"quick_entry": 0,
|
||||
"read_only": 0,
|
||||
"read_only_onload": 0,
|
||||
"track_seen": 0
|
||||
}
|
||||
@@ -1,9 +0,0 @@
|
||||
# Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors
|
||||
# License: GNU General Public License v3. See license.txt
|
||||
|
||||
|
||||
from frappe.model.document import Document
|
||||
|
||||
|
||||
class AppraisalGoal(Document):
|
||||
pass
|
||||
@@ -1 +0,0 @@
|
||||
Standard set of goals for an Employee / Designation / Job Profile. New Appraisal transactions can be created from the Template.
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user