diff --git a/.git-blame-ignore-revs b/.git-blame-ignore-revs index 6eaf9ccec66..88049be32d4 100644 --- a/.git-blame-ignore-revs +++ b/.git-blame-ignore-revs @@ -20,3 +20,6 @@ b147b85e6ac19a9220cd1e2958a6ebd99373283a # sort and cleanup imports 915b34391c2066dfc83e60a5813c5a877cebe7ac + +# removing six compatibility layer +8fe5feb6a4372bf5f2dfaf65fca41bbcc25c8ce7 diff --git a/.github/CONTRIBUTING.md b/.github/CONTRIBUTING.md index 511b682f371..1cf9a5bd9b5 100644 --- a/.github/CONTRIBUTING.md +++ b/.github/CONTRIBUTING.md @@ -23,7 +23,7 @@ If your issue is not clear or does not meet the guidelines, then it will be clos 1. **Steps to Reproduce:** The bug report must have a list of steps needed to reproduce a bug. If we cannot reproduce it, then we cannot solve it. 1. **Version Number:** Please add the version number in your report. Often a bug is fixed in the latest version 1. **Clear Title:** Add a clear subject to your bug report like "Unable to submit Purchase Order without Basic Rate" instead of just "Cannot Submit" -1. **Screenshots:** Screenshots are a great way of communicating the issues. Try adding annotations or using LiceCAP to take a screencast in `gif`. +1. **Screenshots:** Screenshots are a great way of communicating issues. Try adding annotations or using LiceCAP to take a screencast in `gif`. ### Feature Request Guidelines diff --git a/.github/helper/.flake8_strict b/.github/helper/.flake8_strict index 4c7f5f82cfb..a79137d7c32 100644 --- a/.github/helper/.flake8_strict +++ b/.github/helper/.flake8_strict @@ -1,6 +1,8 @@ [flake8] ignore = B007, + B009, + B010, B950, E101, E111, diff --git a/.github/helper/documentation.py b/.github/helper/documentation.py index 91983d3eae5..378983e95f2 100644 --- a/.github/helper/documentation.py +++ b/.github/helper/documentation.py @@ -24,6 +24,8 @@ def docs_link_exists(body): parts = parsed_url.path.split('/') if len(parts) == 5 and parts[1] == "frappe" and parts[2] in docs_repos: return True + elif parsed_url.netloc == "docs.erpnext.com": + return True if __name__ == "__main__": diff --git a/.github/helper/install.sh b/.github/helper/install.sh index ac623e947db..85f146d3519 100644 --- a/.github/helper/install.sh +++ b/.github/helper/install.sh @@ -37,6 +37,9 @@ sed -i 's/socketio:/# socketio:/g' Procfile sed -i 's/redis_socketio:/# redis_socketio:/g' Procfile bench get-app erpnext "${GITHUB_WORKSPACE}" + +if [ "$TYPE" == "server" ]; then bench setup requirements --dev; fi + bench start &> bench_run_logs.txt & bench --site test_site reinstall --yes bench build --app frappe diff --git a/.github/helper/semgrep_rules/README.md b/.github/helper/semgrep_rules/README.md deleted file mode 100644 index 670d8d280f2..00000000000 --- a/.github/helper/semgrep_rules/README.md +++ /dev/null @@ -1,38 +0,0 @@ -# Semgrep linting - -## What is semgrep? -Semgrep or "semantic grep" is language agnostic static analysis tool. In simple terms semgrep is syntax-aware `grep`, so unlike regex it doesn't get confused by different ways of writing same thing or whitespaces or code split in multiple lines etc. - -Example: - -To check if a translate function is using f-string or not the regex would be `r"_\(\s*f[\"']"` while equivalent rule in semgrep would be `_(f"...")`. As semgrep knows grammer of language it takes care of unnecessary whitespace, type of quotation marks etc. - -You can read more such examples in `.github/helper/semgrep_rules` directory. - -# Why/when to use this? -We want to maintain quality of contributions, at the same time remembering all the good practices can be pain to deal with while evaluating contributions. Using semgrep if you can translate "best practice" into a rule then it can automate the task for us. - -## Running locally - -Install semgrep using homebrew `brew install semgrep` or pip `pip install semgrep`. - -To run locally use following command: - -`semgrep --config=.github/helper/semgrep_rules [file/folder names]` - -## Testing -semgrep allows testing the tests. Refer to this page: https://semgrep.dev/docs/writing-rules/testing-rules/ - -When writing new rules you should write few positive and few negative cases as shown in the guide and current tests. - -To run current tests: `semgrep --test --test-ignore-todo .github/helper/semgrep_rules` - - -## Reference - -If you are new to Semgrep read following pages to get started on writing/modifying rules: - -- https://semgrep.dev/docs/getting-started/ -- https://semgrep.dev/docs/writing-rules/rule-syntax -- https://semgrep.dev/docs/writing-rules/pattern-examples/ -- https://semgrep.dev/docs/writing-rules/rule-ideas/#common-use-cases diff --git a/.github/helper/semgrep_rules/frappe_correctness.py b/.github/helper/semgrep_rules/frappe_correctness.py deleted file mode 100644 index 83d4acfe4ab..00000000000 --- a/.github/helper/semgrep_rules/frappe_correctness.py +++ /dev/null @@ -1,64 +0,0 @@ -import frappe -from frappe import _ - -from frappe.model.document import Document - - -# ruleid: frappe-modifying-but-not-comitting -def on_submit(self): - if self.value_of_goods == 0: - frappe.throw(_('Value of goods cannot be 0')) - self.status = 'Submitted' - - -# ok: frappe-modifying-but-not-comitting -def on_submit(self): - if self.value_of_goods == 0: - frappe.throw(_('Value of goods cannot be 0')) - self.status = 'Submitted' - self.db_set('status', 'Submitted') - -# ok: frappe-modifying-but-not-comitting -def on_submit(self): - if self.value_of_goods == 0: - frappe.throw(_('Value of goods cannot be 0')) - x = "y" - self.status = x - self.db_set('status', x) - - -# ok: frappe-modifying-but-not-comitting -def on_submit(self): - x = "y" - self.status = x - self.save() - -# ruleid: frappe-modifying-but-not-comitting-other-method -class DoctypeClass(Document): - def on_submit(self): - self.good_method() - self.tainted_method() - - def tainted_method(self): - self.status = "uptate" - - -# ok: frappe-modifying-but-not-comitting-other-method -class DoctypeClass(Document): - def on_submit(self): - self.good_method() - self.tainted_method() - - def tainted_method(self): - self.status = "update" - self.db_set("status", "update") - -# ok: frappe-modifying-but-not-comitting-other-method -class DoctypeClass(Document): - def on_submit(self): - self.good_method() - self.tainted_method() - self.save() - - def tainted_method(self): - self.status = "uptate" diff --git a/.github/helper/semgrep_rules/frappe_correctness.yml b/.github/helper/semgrep_rules/frappe_correctness.yml deleted file mode 100644 index d9603e89aa4..00000000000 --- a/.github/helper/semgrep_rules/frappe_correctness.yml +++ /dev/null @@ -1,133 +0,0 @@ -# This file specifies rules for correctness according to how frappe doctype data model works. - -rules: -- id: frappe-modifying-but-not-comitting - patterns: - - pattern: | - def $METHOD(self, ...): - ... - self.$ATTR = ... - - pattern-not: | - def $METHOD(self, ...): - ... - self.$ATTR = ... - ... - self.db_set(..., self.$ATTR, ...) - - pattern-not: | - def $METHOD(self, ...): - ... - self.$ATTR = $SOME_VAR - ... - self.db_set(..., $SOME_VAR, ...) - - pattern-not: | - def $METHOD(self, ...): - ... - self.$ATTR = $SOME_VAR - ... - self.save() - - metavariable-regex: - metavariable: '$ATTR' - # this is negative look-ahead, add more attrs to ignore like (ignore|ignore_this_too|ignore_me) - regex: '^(?!ignore_linked_doctypes|status_updater)(.*)$' - - metavariable-regex: - metavariable: "$METHOD" - regex: "(on_submit|on_cancel)" - message: | - DocType modified in self.$METHOD. Please check if modification of self.$ATTR is commited to database. - languages: [python] - severity: ERROR - -- id: frappe-modifying-but-not-comitting-other-method - patterns: - - pattern: | - class $DOCTYPE(...): - def $METHOD(self, ...): - ... - self.$ANOTHER_METHOD() - ... - - def $ANOTHER_METHOD(self, ...): - ... - self.$ATTR = ... - - pattern-not: | - class $DOCTYPE(...): - def $METHOD(self, ...): - ... - self.$ANOTHER_METHOD() - ... - - def $ANOTHER_METHOD(self, ...): - ... - self.$ATTR = ... - ... - self.db_set(..., self.$ATTR, ...) - - pattern-not: | - class $DOCTYPE(...): - def $METHOD(self, ...): - ... - self.$ANOTHER_METHOD() - ... - - def $ANOTHER_METHOD(self, ...): - ... - self.$ATTR = $SOME_VAR - ... - self.db_set(..., $SOME_VAR, ...) - - pattern-not: | - class $DOCTYPE(...): - def $METHOD(self, ...): - ... - self.$ANOTHER_METHOD() - ... - self.save() - def $ANOTHER_METHOD(self, ...): - ... - self.$ATTR = ... - - metavariable-regex: - metavariable: "$METHOD" - regex: "(on_submit|on_cancel)" - message: | - self.$ANOTHER_METHOD is called from self.$METHOD, check if changes to self.$ATTR are commited to database. - languages: [python] - severity: ERROR - -- id: frappe-print-function-in-doctypes - pattern: print(...) - message: | - Did you mean to leave this print statement in? Consider using msgprint or logger instead of print statement. - languages: [python] - severity: WARNING - paths: - include: - - "*/**/doctype/*" - -- id: frappe-modifying-child-tables-while-iterating - pattern-either: - - pattern: | - for $ROW in self.$TABLE: - ... - self.remove(...) - - pattern: | - for $ROW in self.$TABLE: - ... - self.append(...) - message: | - Child table being modified while iterating on it. - languages: [python] - severity: ERROR - paths: - include: - - "*/**/doctype/*" - -- id: frappe-same-key-assigned-twice - pattern-either: - - pattern: | - {..., $X: $A, ..., $X: $B, ...} - - pattern: | - dict(..., ($X, $A), ..., ($X, $B), ...) - - pattern: | - _dict(..., ($X, $A), ..., ($X, $B), ...) - message: | - key `$X` is uselessly assigned twice. This could be a potential bug. - languages: [python] - severity: ERROR diff --git a/.github/helper/semgrep_rules/report.py b/.github/helper/semgrep_rules/report.py deleted file mode 100644 index ff278408e18..00000000000 --- a/.github/helper/semgrep_rules/report.py +++ /dev/null @@ -1,15 +0,0 @@ -from frappe import _ - - -# ruleid: frappe-missing-translate-function-in-report-python -{"label": "Field Label"} - -# ruleid: frappe-missing-translate-function-in-report-python -dict(label="Field Label") - - -# ok: frappe-missing-translate-function-in-report-python -{"label": _("Field Label")} - -# ok: frappe-missing-translate-function-in-report-python -dict(label=_("Field Label")) diff --git a/.github/helper/semgrep_rules/report.yml b/.github/helper/semgrep_rules/report.yml deleted file mode 100644 index 7f3dd011dc1..00000000000 --- a/.github/helper/semgrep_rules/report.yml +++ /dev/null @@ -1,21 +0,0 @@ -rules: -- id: frappe-missing-translate-function-in-report-python - paths: - include: - - "**/report" - exclude: - - "**/regional" - pattern-either: - - patterns: - - pattern: | - {..., "label": "...", ...} - - pattern-not: | - {..., "label": _("..."), ...} - - patterns: - - pattern: dict(..., label="...", ...) - - pattern-not: dict(..., label=_("..."), ...) - message: | - All user facing text must be wrapped in translate function. Please refer to translation documentation. https://frappeframework.com/docs/user/en/guides/basics/translations - languages: [python] - severity: ERROR - diff --git a/.github/helper/semgrep_rules/security.py b/.github/helper/semgrep_rules/security.py deleted file mode 100644 index f477d7c1768..00000000000 --- a/.github/helper/semgrep_rules/security.py +++ /dev/null @@ -1,6 +0,0 @@ -def function_name(input): - # ruleid: frappe-codeinjection-eval - eval(input) - -# ok: frappe-codeinjection-eval -eval("1 + 1") diff --git a/.github/helper/semgrep_rules/security.yml b/.github/helper/semgrep_rules/security.yml deleted file mode 100644 index 8b219792080..00000000000 --- a/.github/helper/semgrep_rules/security.yml +++ /dev/null @@ -1,10 +0,0 @@ -rules: -- id: frappe-codeinjection-eval - patterns: - - pattern-not: eval("...") - - pattern: eval(...) - message: | - Detected the use of eval(). eval() can be dangerous if used to evaluate - dynamic content. Avoid it or use safe_eval(). - languages: [python] - severity: ERROR diff --git a/.github/helper/semgrep_rules/translate.js b/.github/helper/semgrep_rules/translate.js deleted file mode 100644 index 9cdfb75d0be..00000000000 --- a/.github/helper/semgrep_rules/translate.js +++ /dev/null @@ -1,44 +0,0 @@ -// ruleid: frappe-translation-empty-string -__("") -// ruleid: frappe-translation-empty-string -__('') - -// ok: frappe-translation-js-formatting -__('Welcome {0}, get started with ERPNext in just a few clicks.', [full_name]); - -// ruleid: frappe-translation-js-formatting -__(`Welcome ${full_name}, get started with ERPNext in just a few clicks.`); - -// ok: frappe-translation-js-formatting -__('This is fine'); - - -// ok: frappe-translation-trailing-spaces -__('This is fine'); - -// ruleid: frappe-translation-trailing-spaces -__(' this is not ok '); -// ruleid: frappe-translation-trailing-spaces -__('this is not ok '); -// ruleid: frappe-translation-trailing-spaces -__(' this is not ok'); - -// ok: frappe-translation-js-splitting -__('You have {0} subscribers in your mailing list.', [subscribers.length]) - -// todoruleid: frappe-translation-js-splitting -__('You have') + subscribers.length + __('subscribers in your mailing list.') - -// ruleid: frappe-translation-js-splitting -__('You have' + 'subscribers in your mailing list.') - -// ruleid: frappe-translation-js-splitting -__('You have {0} subscribers' + - 'in your mailing list', [subscribers.length]) - -// ok: frappe-translation-js-splitting -__("Ctrl+Enter to add comment") - -// ruleid: frappe-translation-js-splitting -__('You have {0} subscribers \ - in your mailing list', [subscribers.length]) diff --git a/.github/helper/semgrep_rules/translate.py b/.github/helper/semgrep_rules/translate.py deleted file mode 100644 index 9de6aa94f01..00000000000 --- a/.github/helper/semgrep_rules/translate.py +++ /dev/null @@ -1,61 +0,0 @@ -# Examples taken from https://frappeframework.com/docs/user/en/translations -# This file is used for testing the tests. - -from frappe import _ - -full_name = "Jon Doe" -# ok: frappe-translation-python-formatting -_('Welcome {0}, get started with ERPNext in just a few clicks.').format(full_name) - -# ruleid: frappe-translation-python-formatting -_('Welcome %s, get started with ERPNext in just a few clicks.' % full_name) -# ruleid: frappe-translation-python-formatting -_('Welcome %(name)s, get started with ERPNext in just a few clicks.' % {'name': full_name}) - -# ruleid: frappe-translation-python-formatting -_('Welcome {0}, get started with ERPNext in just a few clicks.'.format(full_name)) - - -subscribers = ["Jon", "Doe"] -# ok: frappe-translation-python-formatting -_('You have {0} subscribers in your mailing list.').format(len(subscribers)) - -# ruleid: frappe-translation-python-splitting -_('You have') + len(subscribers) + _('subscribers in your mailing list.') - -# ruleid: frappe-translation-python-splitting -_('You have {0} subscribers \ - in your mailing list').format(len(subscribers)) - -# ok: frappe-translation-python-splitting -_('You have {0} subscribers') \ - + 'in your mailing list' - -# ruleid: frappe-translation-trailing-spaces -msg = _(" You have {0} pending invoice ") -# ruleid: frappe-translation-trailing-spaces -msg = _("You have {0} pending invoice ") -# ruleid: frappe-translation-trailing-spaces -msg = _(" You have {0} pending invoice") - -# ok: frappe-translation-trailing-spaces -msg = ' ' + _("You have {0} pending invoices") + ' ' - -# ruleid: frappe-translation-python-formatting -_(f"can not format like this - {subscribers}") -# ruleid: frappe-translation-python-splitting -_(f"what" + f"this is also not cool") - - -# ruleid: frappe-translation-empty-string -_("") -# ruleid: frappe-translation-empty-string -_('') - - -class Test: - # ok: frappe-translation-python-splitting - def __init__( - args - ): - pass diff --git a/.github/helper/semgrep_rules/translate.yml b/.github/helper/semgrep_rules/translate.yml deleted file mode 100644 index 5f03fb9fd00..00000000000 --- a/.github/helper/semgrep_rules/translate.yml +++ /dev/null @@ -1,64 +0,0 @@ -rules: -- id: frappe-translation-empty-string - pattern-either: - - pattern: _("") - - pattern: __("") - message: | - Empty string is useless for translation. - Please refer: https://frappeframework.com/docs/user/en/translations - languages: [python, javascript, json] - severity: ERROR - -- id: frappe-translation-trailing-spaces - pattern-either: - - pattern: _("=~/(^[ \t]+|[ \t]+$)/") - - pattern: __("=~/(^[ \t]+|[ \t]+$)/") - message: | - Trailing or leading whitespace not allowed in translate strings. - Please refer: https://frappeframework.com/docs/user/en/translations - languages: [python, javascript, json] - severity: ERROR - -- id: frappe-translation-python-formatting - pattern-either: - - pattern: _("..." % ...) - - pattern: _("...".format(...)) - - pattern: _(f"...") - message: | - Only positional formatters are allowed and formatting should not be done before translating. - Please refer: https://frappeframework.com/docs/user/en/translations - languages: [python] - severity: ERROR - -- id: frappe-translation-js-formatting - patterns: - - pattern: __(`...`) - - pattern-not: __("...") - message: | - Template strings are not allowed for text formatting. - Please refer: https://frappeframework.com/docs/user/en/translations - languages: [javascript, json] - severity: ERROR - -- id: frappe-translation-python-splitting - pattern-either: - - pattern: _(...) + _(...) - - pattern: _("..." + "...") - - pattern-regex: '[\s\.]_\([^\)]*\\\s*' # lines broken by `\` - - pattern-regex: '[\s\.]_\(\s*\n' # line breaks allowed by python for using ( ) - message: | - Do not split strings inside translate function. Do not concatenate using translate functions. - Please refer: https://frappeframework.com/docs/user/en/translations - languages: [python] - severity: ERROR - -- id: frappe-translation-js-splitting - pattern-either: - - pattern-regex: '__\([^\)]*[\\]\s+' - - pattern: __('...' + '...', ...) - - pattern: __('...') + __('...') - message: | - Do not split strings inside translate function. Do not concatenate using translate functions. - Please refer: https://frappeframework.com/docs/user/en/translations - languages: [javascript, json] - severity: ERROR diff --git a/.github/helper/semgrep_rules/ux.js b/.github/helper/semgrep_rules/ux.js deleted file mode 100644 index ae73f9cc603..00000000000 --- a/.github/helper/semgrep_rules/ux.js +++ /dev/null @@ -1,9 +0,0 @@ - -// ok: frappe-missing-translate-function-js -frappe.msgprint('{{ _("Both login and password required") }}'); - -// ruleid: frappe-missing-translate-function-js -frappe.msgprint('What'); - -// ok: frappe-missing-translate-function-js -frappe.throw(' {{ _("Both login and password required") }}. '); diff --git a/.github/helper/semgrep_rules/ux.py b/.github/helper/semgrep_rules/ux.py deleted file mode 100644 index a00d3cd8aef..00000000000 --- a/.github/helper/semgrep_rules/ux.py +++ /dev/null @@ -1,31 +0,0 @@ -import frappe -from frappe import msgprint, throw, _ - - -# ruleid: frappe-missing-translate-function-python -throw("Error Occured") - -# ruleid: frappe-missing-translate-function-python -frappe.throw("Error Occured") - -# ruleid: frappe-missing-translate-function-python -frappe.msgprint("Useful message") - -# ruleid: frappe-missing-translate-function-python -msgprint("Useful message") - - -# ok: frappe-missing-translate-function-python -translatedmessage = _("Hello") - -# ok: frappe-missing-translate-function-python -throw(translatedmessage) - -# ok: frappe-missing-translate-function-python -msgprint(translatedmessage) - -# ok: frappe-missing-translate-function-python -msgprint(_("Helpful message")) - -# ok: frappe-missing-translate-function-python -frappe.throw(_("Error occured")) diff --git a/.github/helper/semgrep_rules/ux.yml b/.github/helper/semgrep_rules/ux.yml deleted file mode 100644 index dd667f36c0f..00000000000 --- a/.github/helper/semgrep_rules/ux.yml +++ /dev/null @@ -1,30 +0,0 @@ -rules: -- id: frappe-missing-translate-function-python - pattern-either: - - patterns: - - pattern: frappe.msgprint("...", ...) - - pattern-not: frappe.msgprint(_("..."), ...) - - patterns: - - pattern: frappe.throw("...", ...) - - pattern-not: frappe.throw(_("..."), ...) - message: | - All user facing text must be wrapped in translate function. Please refer to translation documentation. https://frappeframework.com/docs/user/en/guides/basics/translations - languages: [python] - severity: ERROR - -- id: frappe-missing-translate-function-js - pattern-either: - - patterns: - - pattern: frappe.msgprint("...", ...) - - pattern-not: frappe.msgprint(__("..."), ...) - # ignore microtemplating e.g. msgprint("{{ _("server side translation") }}") - - pattern-not: frappe.msgprint("=~/\{\{.*\_.*\}\}/i", ...) - - patterns: - - pattern: frappe.throw("...", ...) - - pattern-not: frappe.throw(__("..."), ...) - # ignore microtemplating - - pattern-not: frappe.throw("=~/\{\{.*\_.*\}\}/i", ...) - message: | - All user facing text must be wrapped in translate function. Please refer to translation documentation. https://frappeframework.com/docs/user/en/guides/basics/translations - languages: [javascript] - severity: ERROR diff --git a/.github/try-on-f-cloud-button.svg b/.github/try-on-f-cloud-button.svg new file mode 100644 index 00000000000..fe0bb2c52df --- /dev/null +++ b/.github/try-on-f-cloud-button.svg @@ -0,0 +1,32 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/.github/workflows/docker-release.yml b/.github/workflows/docker-release.yml index 4b1147e79f9..5b607a99406 100644 --- a/.github/workflows/docker-release.yml +++ b/.github/workflows/docker-release.yml @@ -11,4 +11,4 @@ jobs: - name: curl run: | apk add curl bash - curl -s -X POST -H "Content-Type: application/json" -H "Accept: application/json" -H "Travis-API-Version: 3" -H "Authorization: token ${{ secrets.TRAVIS_CI_TOKEN }}" -d '{"request":{"branch":"master"}}' https://api.travis-ci.com/repo/frappe%2Ffrappe_docker/requests + curl -X POST -H "Accept: application/vnd.github.v3+json" -H "Authorization: Bearer ${{ secrets.CI_PAT }}" https://api.github.com/repos/frappe/frappe_docker/actions/workflows/build_stable.yml/dispatches -d '{"ref":"main"}' diff --git a/.github/workflows/linters.yml b/.github/workflows/linters.yml index 16e490a4609..ebb88c9edac 100644 --- a/.github/workflows/linters.yml +++ b/.github/workflows/linters.yml @@ -10,13 +10,6 @@ jobs: runs-on: ubuntu-latest steps: - uses: actions/checkout@v2 - - uses: returntocorp/semgrep-action@v1 - env: - SEMGREP_TIMEOUT: 120 - with: - config: >- - r/python.lang.correctness - .github/helper/semgrep_rules - name: Set up Python 3.8 uses: actions/setup-python@v2 @@ -25,3 +18,14 @@ jobs: - name: Install and Run Pre-commit uses: pre-commit/action@v2.0.3 + + - name: Download Semgrep rules + run: git clone --depth 1 https://github.com/frappe/semgrep-rules.git frappe-semgrep-rules + + - uses: returntocorp/semgrep-action@v1 + env: + SEMGREP_TIMEOUT: 120 + with: + config: >- + r/python.lang.correctness + ./frappe-semgrep-rules/rules diff --git a/.github/workflows/patch.yml b/.github/workflows/patch.yml index 92a19621d15..97bccf5d56a 100644 --- a/.github/workflows/patch.yml +++ b/.github/workflows/patch.yml @@ -86,4 +86,27 @@ jobs: cd ~/frappe-bench/ wget https://erpnext.com/files/v10-erpnext.sql.gz bench --site test_site --force restore ~/frappe-bench/v10-erpnext.sql.gz + + git -C "apps/frappe" remote set-url upstream https://github.com/frappe/frappe.git + git -C "apps/erpnext" remote set-url upstream https://github.com/frappe/erpnext.git + + for version in $(seq 12 13) + do + 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 + + git -C "apps/frappe" checkout -q -f $branch_name + git -C "apps/erpnext" checkout -q -f $branch_name + + bench setup requirements --python + bench --site test_site migrate + done + + + echo "Updating to latest version" + git -C "apps/frappe" checkout -q -f "${GITHUB_BASE_REF:-${GITHUB_REF##*/}}" + git -C "apps/erpnext" checkout -q -f "$GITHUB_SHA" bench --site test_site migrate diff --git a/.github/workflows/server-tests.yml b/.github/workflows/server-tests.yml index 71e9c2cd138..77c0aee195b 100644 --- a/.github/workflows/server-tests.yml +++ b/.github/workflows/server-tests.yml @@ -91,6 +91,8 @@ jobs: - name: Install run: bash ${GITHUB_WORKSPACE}/.github/helper/install.sh + env: + TYPE: server - name: Run Tests run: cd ~/frappe-bench/ && bench --site test_site run-parallel-tests --app erpnext --use-orchestrator --with-coverage @@ -99,34 +101,10 @@ jobs: CI_BUILD_ID: ${{ github.run_id }} ORCHESTRATOR_URL: http://test-orchestrator.frappe.io - - name: Upload Coverage Data - run: | - cp ~/frappe-bench/sites/.coverage ${GITHUB_WORKSPACE} - cd ${GITHUB_WORKSPACE} - pip3 install coverage==5.5 - pip3 install coveralls==3.0.1 - coveralls - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - COVERALLS_REPO_TOKEN: ${{ secrets.COVERALLS_TOKEN }} - COVERALLS_FLAG_NAME: run-${{ matrix.container }} - COVERALLS_SERVICE_NAME: ${{ github.event_name == 'pull_request' && 'github' || 'github-actions' }} - COVERALLS_PARALLEL: true - - coveralls: - name: Coverage Wrap Up - needs: test - container: python:3-slim - runs-on: ubuntu-latest - steps: - - name: Clone - uses: actions/checkout@v2 - - - name: Coveralls Finished - run: | - cd ${GITHUB_WORKSPACE} - pip3 install coverage==5.5 - pip3 install coveralls==3.0.1 - coveralls --finish - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + - name: Upload coverage data + uses: codecov/codecov-action@v2 + with: + name: MariaDB + fail_ci_if_error: true + files: /home/runner/frappe-bench/sites/coverage.xml + verbose: true diff --git a/.github/workflows/ui-tests.yml b/.github/workflows/ui-tests.yml index 658892c20ef..d765f0482c8 100644 --- a/.github/workflows/ui-tests.yml +++ b/.github/workflows/ui-tests.yml @@ -104,6 +104,8 @@ jobs: - name: Build Assets run: cd ~/frappe-bench/ && bench build + env: + CI: Yes - name: UI Tests run: cd ~/frappe-bench/ && bench --site test_site run-ui-tests erpnext --headless diff --git a/.mergify.yml b/.mergify.yml new file mode 100644 index 00000000000..f3d04096cfc --- /dev/null +++ b/.mergify.yml @@ -0,0 +1,58 @@ +pull_request_rules: + - name: Auto-close PRs on stable branch + conditions: + - and: + - and: + - author!=surajshetty3416 + - author!=gavindsouza + - author!=rohitwaghchaure + - author!=nabinhait + - or: + - base=version-13 + - base=version-12 + actions: + close: + comment: + message: | + @{{author}}, thanks for the contribution, but we do not accept pull requests on a stable branch. Please raise PR on an appropriate hotfix branch. + https://github.com/frappe/erpnext/wiki/Pull-Request-Checklist#which-branch + + - name: backport to version-13-hotfix + conditions: + - label="backport version-13-hotfix" + actions: + backport: + branches: + - version-13-hotfix + assignees: + - "{{ author }}" + + - name: backport to version-13-pre-release + conditions: + - label="backport version-13-pre-release" + actions: + backport: + branches: + - version-13-pre-release + assignees: + - "{{ author }}" + + - name: backport to version-12-hotfix + conditions: + - label="backport version-12-hotfix" + actions: + backport: + branches: + - version-12-hotfix + assignees: + - "{{ author }}" + + - name: backport to version-12-pre-release + conditions: + - label="backport version-12-pre-release" + actions: + backport: + branches: + - version-12-pre-release + assignees: + - "{{ author }}" \ No newline at end of file diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 2b3a471f774..b74d9a640da 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -20,6 +20,9 @@ repos: rev: 3.9.2 hooks: - id: flake8 + additional_dependencies: [ + 'flake8-bugbear', + ] args: ['--config', '.github/helper/.flake8_strict'] exclude: ".*setup.py$" diff --git a/.snyk b/.snyk deleted file mode 100644 index 140f3edd846..00000000000 --- a/.snyk +++ /dev/null @@ -1,8 +0,0 @@ -# Snyk (https://snyk.io) policy file, patches or ignores known vulnerabilities. -version: v1.14.0 -ignore: {} -# patches apply the minimum changes required to fix a vulnerability -patch: - SNYK-JS-LODASH-450202: - - cypress > getos > async > lodash: - patched: '2020-01-31T01:35:12.802Z' diff --git a/README.md b/README.md index c6fc2512445..96093531d33 100644 --- a/README.md +++ b/README.md @@ -7,7 +7,8 @@ [![CI](https://github.com/frappe/erpnext/actions/workflows/server-tests.yml/badge.svg?branch=develop)](https://github.com/frappe/erpnext/actions/workflows/server-tests.yml) [![Open Source Helpers](https://www.codetriage.com/frappe/erpnext/badges/users.svg)](https://www.codetriage.com/frappe/erpnext) -[![Coverage Status](https://coveralls.io/repos/github/frappe/erpnext/badge.svg?branch=develop)](https://coveralls.io/github/frappe/erpnext?branch=develop) +[![codecov](https://codecov.io/gh/frappe/erpnext/branch/develop/graph/badge.svg?token=0TwvyUg3I5)](https://codecov.io/gh/frappe/erpnext) +[![docker pulls](https://img.shields.io/docker/pulls/frappe/erpnext-worker.svg)](https://hub.docker.com/r/frappe/erpnext-worker) [https://erpnext.com](https://erpnext.com) @@ -39,6 +40,12 @@ ERPNext is built on the [Frappe Framework](https://github.com/frappe/frappe), a --- +
+ + + +
+ ### Containerized Installation Use docker to deploy ERPNext in production or for development of [Frappe](https://github.com/frappe/frappe) apps. See https://github.com/frappe/frappe_docker for more details. @@ -49,14 +56,6 @@ The Easy Way: our install script for bench will install all dependencies (e.g. M New passwords will be created for the ERPNext "Administrator" user, the MariaDB root user, and the frappe user (the script displays the passwords and saves them to ~/frappe_passwords.txt). -### Virtual Image - -You can download a virtual image to run ERPNext in a virtual machine on your local system. - -- [ERPNext Download](http://erpnext.com/download) - -System and user credentials are listed on the download page. - --- ## License @@ -77,6 +76,12 @@ The ERPNext code is licensed as GNU General Public License (v3) and the Document --- +## Learning + +1. [Frappe School](https://frappe.school) - Learn Frappe Framework and ERPNext from the various courses by the maintainers or from the community. + +--- + ## Logo and Trademark The brand name ERPNext and the logo are trademarks of Frappe Technologies Pvt. Ltd. diff --git a/codecov.yml b/codecov.yml new file mode 100644 index 00000000000..67bd4454ef1 --- /dev/null +++ b/codecov.yml @@ -0,0 +1,17 @@ +codecov: + require_ci_to_pass: yes + +coverage: + status: + project: + default: + target: auto + threshold: 0.5% + +comment: + layout: "diff, files" + require_changes: true + after_n_builds: 3 + +ignore: + - "erpnext/demo" diff --git a/cypress/integration/test_organizational_chart_desktop.js b/cypress/integration/test_organizational_chart_desktop.js index 39b00d32635..464cce48d03 100644 --- a/cypress/integration/test_organizational_chart_desktop.js +++ b/cypress/integration/test_organizational_chart_desktop.js @@ -6,7 +6,7 @@ context('Organizational Chart', () => { it('navigates to org chart', () => { cy.visit('/app'); - cy.awesomebar('Organizational Chart'); + cy.visit('/app/organizational-chart'); cy.url().should('include', '/organizational-chart'); cy.window().its('frappe.csrf_token').then(csrf_token => { @@ -24,7 +24,7 @@ context('Organizational Chart', () => { cy.get('.frappe-control[data-fieldname=company] input').focus().as('input'); cy.get('@input') .clear({ force: true }) - .type('Test Org Chart{enter}', { force: true }) + .type('Test Org Chart{downarrow}{enter}', { force: true }) .blur({ force: true }); }); }); diff --git a/cypress/integration/test_organizational_chart_mobile.js b/cypress/integration/test_organizational_chart_mobile.js index 6e751513967..971ac6d3ef3 100644 --- a/cypress/integration/test_organizational_chart_mobile.js +++ b/cypress/integration/test_organizational_chart_mobile.js @@ -7,7 +7,7 @@ context('Organizational Chart Mobile', () => { it('navigates to org chart', () => { cy.viewport(375, 667); cy.visit('/app'); - cy.awesomebar('Organizational Chart'); + cy.visit('/app/organizational-chart'); cy.url().should('include', '/organizational-chart'); cy.window().its('frappe.csrf_token').then(csrf_token => { @@ -25,7 +25,7 @@ context('Organizational Chart Mobile', () => { cy.get('.frappe-control[data-fieldname=company] input').focus().as('input'); cy.get('@input') .clear({ force: true }) - .type('Test Org Chart{enter}', { force: true }) + .type('Test Org Chart{downarrow}{enter}', { force: true }) .blur({ force: true }); }); }); diff --git a/erpnext/__init__.py b/erpnext/__init__.py index 45218276f68..9d99ebb7bb6 100644 --- a/erpnext/__init__.py +++ b/erpnext/__init__.py @@ -1,6 +1,3 @@ -# -*- coding: utf-8 -*- -from __future__ import unicode_literals - import inspect import frappe diff --git a/erpnext/accounts/custom/address.py b/erpnext/accounts/custom/address.py index a6d08d8ff61..551048e50b4 100644 --- a/erpnext/accounts/custom/address.py +++ b/erpnext/accounts/custom/address.py @@ -10,6 +10,7 @@ from frappe.contacts.doctype.address.address import ( class ERPNextAddress(Address): def validate(self): self.validate_reference() + self.update_compnay_address() super(ERPNextAddress, self).validate() def link_address(self): @@ -19,6 +20,11 @@ class ERPNextAddress(Address): return super(ERPNextAddress, self).link_address() + def update_compnay_address(self): + for link in self.get('links'): + if link.link_doctype == 'Company': + self.is_your_company_address = 1 + def validate_reference(self): if self.is_your_company_address and not [ row for row in self.links if row.link_doctype == "Company" diff --git a/erpnext/accounts/dashboard_chart_source/account_balance_timeline/account_balance_timeline.py b/erpnext/accounts/dashboard_chart_source/account_balance_timeline/account_balance_timeline.py index 5eb857719a9..1c1364ed111 100644 --- a/erpnext/accounts/dashboard_chart_source/account_balance_timeline/account_balance_timeline.py +++ b/erpnext/accounts/dashboard_chart_source/account_balance_timeline/account_balance_timeline.py @@ -1,7 +1,6 @@ # Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors # License: GNU General Public License v3. See license.txt -from __future__ import unicode_literals import frappe from frappe import _ diff --git a/erpnext/accounts/deferred_revenue.py b/erpnext/accounts/deferred_revenue.py index bcd07718a59..5df8269f754 100644 --- a/erpnext/accounts/deferred_revenue.py +++ b/erpnext/accounts/deferred_revenue.py @@ -1,5 +1,3 @@ -from __future__ import unicode_literals - import frappe from frappe import _ from frappe.email import sendmail_to_system_managers @@ -374,12 +372,15 @@ def make_gl_entries(doc, credit_account, debit_account, against, try: make_gl_entries(gl_entries, cancel=(doc.docstatus == 2), merge_entries=True) frappe.db.commit() - except Exception: - frappe.db.rollback() - traceback = frappe.get_traceback() - frappe.log_error(message=traceback) + except Exception as e: + if frappe.flags.in_test: + raise e + else: + frappe.db.rollback() + traceback = frappe.get_traceback() + frappe.log_error(message=traceback) - frappe.flags.deferred_accounting_error = True + frappe.flags.deferred_accounting_error = True def send_mail(deferred_process): title = _("Error while processing deferred accounting for {0}").format(deferred_process) diff --git a/erpnext/accounts/doctype/__init__.py b/erpnext/accounts/doctype/__init__.py index baffc488252..e69de29bb2d 100644 --- a/erpnext/accounts/doctype/__init__.py +++ b/erpnext/accounts/doctype/__init__.py @@ -1 +0,0 @@ -from __future__ import unicode_literals diff --git a/erpnext/accounts/doctype/account/__init__.py b/erpnext/accounts/doctype/account/__init__.py index baffc488252..e69de29bb2d 100644 --- a/erpnext/accounts/doctype/account/__init__.py +++ b/erpnext/accounts/doctype/account/__init__.py @@ -1 +0,0 @@ -from __future__ import unicode_literals diff --git a/erpnext/accounts/doctype/account/account.py b/erpnext/accounts/doctype/account/account.py index f6198eb23ba..f8a06c7243f 100644 --- a/erpnext/accounts/doctype/account/account.py +++ b/erpnext/accounts/doctype/account/account.py @@ -1,13 +1,14 @@ # Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors # License: GNU General Public License v3. See license.txt -from __future__ import unicode_literals import frappe from frappe import _, throw from frappe.utils import cint, cstr from frappe.utils.nestedset import NestedSet, get_ancestors_of, get_descendants_of +import erpnext + class RootNotEditable(frappe.ValidationError): pass class BalanceMismatchError(frappe.ValidationError): pass @@ -196,7 +197,7 @@ class Account(NestedSet): "company": company, # parent account's currency should be passed down to child account's curreny # if it is None, it picks it up from default company currency, which might be unintended - "account_currency": self.account_currency, + "account_currency": erpnext.get_company_currency(company), "parent_account": parent_acc_name_map[company] }) @@ -207,8 +208,7 @@ class Account(NestedSet): # update the parent company's value in child companies doc = frappe.get_doc("Account", child_account) parent_value_changed = False - for field in ['account_type', 'account_currency', - 'freeze_account', 'balance_must_be']: + for field in ['account_type', 'freeze_account', 'balance_must_be']: if doc.get(field) != self.get(field): parent_value_changed = True doc.set(field, self.get(field)) diff --git a/erpnext/accounts/doctype/account/account_tree.js b/erpnext/accounts/doctype/account/account_tree.js index 7516134baf5..a3ef38465ec 100644 --- a/erpnext/accounts/doctype/account/account_tree.js +++ b/erpnext/accounts/doctype/account/account_tree.js @@ -45,6 +45,50 @@ frappe.treeview_settings["Account"] = { ], root_label: "Accounts", get_tree_nodes: 'erpnext.accounts.utils.get_children', + on_get_node: function(nodes, deep=false) { + if (frappe.boot.user.can_read.indexOf("GL Entry") == -1) return; + + let accounts = []; + if (deep) { + // in case of `get_all_nodes` + accounts = nodes.reduce((acc, node) => [...acc, ...node.data], []); + } else { + accounts = nodes; + } + + const get_balances = frappe.call({ + method: 'erpnext.accounts.utils.get_account_balances', + args: { + accounts: accounts, + company: cur_tree.args.company + }, + }); + + get_balances.then(r => { + if (!r.message || r.message.length == 0) return; + + for (let account of r.message) { + + const node = cur_tree.nodes && cur_tree.nodes[account.value]; + if (!node || node.is_root) continue; + + // show Dr if positive since balance is calculated as debit - credit else show Cr + const balance = account.balance_in_account_currency || account.balance; + const dr_or_cr = balance > 0 ? "Dr": "Cr"; + const format = (value, currency) => format_currency(Math.abs(value), currency); + + if (account.balance!==undefined) { + node.parent && node.parent.find('.balance-area').remove(); + $('' + + (account.balance_in_account_currency ? + (format(account.balance_in_account_currency, account.account_currency) + " / ") : "") + + format(account.balance, account.company_currency) + + " " + dr_or_cr + + '').insertBefore(node.$ul); + } + } + }); + }, add_tree_node: 'erpnext.accounts.utils.add_ac', menu_items:[ { @@ -122,24 +166,6 @@ frappe.treeview_settings["Account"] = { } }, "add"); }, - onrender: function(node) { - if (frappe.boot.user.can_read.indexOf("GL Entry") !== -1) { - - // show Dr if positive since balance is calculated as debit - credit else show Cr - let balance = node.data.balance_in_account_currency || node.data.balance; - let dr_or_cr = balance > 0 ? "Dr": "Cr"; - - if (node.data && node.data.balance!==undefined) { - $('' - + (node.data.balance_in_account_currency ? - (format_currency(Math.abs(node.data.balance_in_account_currency), - node.data.account_currency) + " / ") : "") - + format_currency(Math.abs(node.data.balance), node.data.company_currency) - + " " + dr_or_cr - + '').insertBefore(node.$ul); - } - } - }, toolbar: [ { label:__("Add Child"), @@ -150,7 +176,7 @@ frappe.treeview_settings["Account"] = { && node.expandable && !node.hide_add; }, click: function() { - var me = frappe.treeview_settings['Account'].treeview; + var me = frappe.views.trees['Account']; me.new_node(); }, btnClass: "hidden-xs" diff --git a/erpnext/accounts/doctype/account/chart_of_accounts/chart_of_accounts.py b/erpnext/accounts/doctype/account/chart_of_accounts/chart_of_accounts.py index d6ccd169362..a8de06cc6c3 100644 --- a/erpnext/accounts/doctype/account/chart_of_accounts/chart_of_accounts.py +++ b/erpnext/accounts/doctype/account/chart_of_accounts/chart_of_accounts.py @@ -1,6 +1,5 @@ # Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors # License: GNU General Public License v3. See license.txt -from __future__ import unicode_literals import json import os @@ -8,21 +7,20 @@ import os import frappe from frappe.utils import cstr from frappe.utils.nestedset import rebuild_tree -from six import iteritems from unidecode import unidecode -def create_charts(company, chart_template=None, existing_company=None, custom_chart=None): +def create_charts(company, chart_template=None, existing_company=None, custom_chart=None, from_coa_importer=None): chart = custom_chart or get_chart(chart_template, existing_company) if chart: accounts = [] def _import_accounts(children, parent, root_type, root_account=False): - for account_name, child in iteritems(children): + for account_name, child in children.items(): if root_account: root_type = child.get("root_type") - if account_name not in ["account_number", "account_type", + if account_name not in ["account_name", "account_number", "account_type", "root_type", "is_group", "tax_rate"]: account_number = cstr(child.get("account_number")).strip() @@ -35,7 +33,7 @@ def create_charts(company, chart_template=None, existing_company=None, custom_ch account = frappe.get_doc({ "doctype": "Account", - "account_name": account_name, + "account_name": child.get('account_name') if from_coa_importer else account_name, "company": company, "parent_account": parent, "is_group": is_group, @@ -81,7 +79,7 @@ def add_suffix_if_duplicate(account_name, account_number, accounts): def identify_is_group(child): if child.get("is_group"): is_group = child.get("is_group") - elif len(set(child.keys()) - set(["account_type", "root_type", "is_group", "tax_rate", "account_number"])): + elif len(set(child.keys()) - set(["account_name", "account_type", "root_type", "is_group", "tax_rate", "account_number"])): is_group = 1 else: is_group = 0 @@ -201,7 +199,7 @@ def validate_bank_account(coa, bank_account): if chart: def _get_account_names(account_master): - for account_name, child in iteritems(account_master): + for account_name, child in account_master.items(): if account_name not in ["account_number", "account_type", "root_type", "is_group", "tax_rate"]: accounts.append(account_name) @@ -213,7 +211,7 @@ def validate_bank_account(coa, bank_account): return (bank_account in accounts) @frappe.whitelist() -def build_tree_from_json(chart_template, chart_data=None): +def build_tree_from_json(chart_template, chart_data=None, from_coa_importer=False): ''' get chart template from its folder and parse the json to be rendered as tree ''' chart = chart_data or get_chart(chart_template) @@ -224,11 +222,14 @@ def build_tree_from_json(chart_template, chart_data=None): accounts = [] def _import_accounts(children, parent): ''' recursively called to form a parent-child based list of dict from chart template ''' - for account_name, child in iteritems(children): + for account_name, child in children.items(): account = {} - if account_name in ["account_number", "account_type",\ + if account_name in ["account_name", "account_number", "account_type",\ "root_type", "is_group", "tax_rate"]: continue + if from_coa_importer: + account_name = child['account_name'] + account['parent_account'] = parent account['expandable'] = True if identify_is_group(child) else False account['value'] = (cstr(child.get('account_number')).strip() + ' - ' + account_name) \ diff --git a/erpnext/accounts/doctype/account/chart_of_accounts/import_from_openerp.py b/erpnext/accounts/doctype/account/chart_of_accounts/import_from_openerp.py index 72223573a23..79001d77053 100644 --- a/erpnext/accounts/doctype/account/chart_of_accounts/import_from_openerp.py +++ b/erpnext/accounts/doctype/account/chart_of_accounts/import_from_openerp.py @@ -4,7 +4,6 @@ """ Import chart of accounts from OpenERP sources """ -from __future__ import print_function, unicode_literals import ast import json @@ -13,7 +12,6 @@ from xml.etree import ElementTree as ET import frappe from frappe.utils.csvutils import read_csv_content -from six import iteritems path = "/Users/nabinhait/projects/odoo/addons" @@ -140,7 +138,7 @@ def get_account_types(root_list, csv_content, prefix=None): def make_maps_for_xml(xml_roots, account_types, country_dir): """make maps for `charts` and `accounts`""" - for model, root_list in iteritems(xml_roots): + for model, root_list in xml_roots.items(): for root in root_list: for node in root[0].findall("record"): if node.get("model")=="account.account.template": diff --git a/erpnext/accounts/doctype/account/chart_of_accounts/verified/standard_chart_of_accounts.py b/erpnext/accounts/doctype/account/chart_of_accounts/verified/standard_chart_of_accounts.py index f058afba6a7..9248ffa6e57 100644 --- a/erpnext/accounts/doctype/account/chart_of_accounts/verified/standard_chart_of_accounts.py +++ b/erpnext/accounts/doctype/account/chart_of_accounts/verified/standard_chart_of_accounts.py @@ -1,7 +1,6 @@ # Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors # License: GNU General Public License v3. See license.txt -from __future__ import unicode_literals from frappe import _ diff --git a/erpnext/accounts/doctype/account/chart_of_accounts/verified/standard_chart_of_accounts_with_account_number.py b/erpnext/accounts/doctype/account/chart_of_accounts/verified/standard_chart_of_accounts_with_account_number.py index 9f339520356..31ae17189a7 100644 --- a/erpnext/accounts/doctype/account/chart_of_accounts/verified/standard_chart_of_accounts_with_account_number.py +++ b/erpnext/accounts/doctype/account/chart_of_accounts/verified/standard_chart_of_accounts_with_account_number.py @@ -1,7 +1,6 @@ # Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors # License: GNU General Public License v3. See license.txt -from __future__ import unicode_literals from frappe import _ diff --git a/erpnext/accounts/doctype/account/test_account.py b/erpnext/accounts/doctype/account/test_account.py index 0c3b33e0b9e..0715823b300 100644 --- a/erpnext/accounts/doctype/account/test_account.py +++ b/erpnext/accounts/doctype/account/test_account.py @@ -1,7 +1,6 @@ # Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors # License: GNU General Public License v3. See license.txt -from __future__ import unicode_literals import unittest diff --git a/erpnext/accounts/doctype/accounting_dimension/accounting_dimension.py b/erpnext/accounts/doctype/accounting_dimension/accounting_dimension.py index af8255f9448..b6112e0cc57 100644 --- a/erpnext/accounts/doctype/accounting_dimension/accounting_dimension.py +++ b/erpnext/accounts/doctype/accounting_dimension/accounting_dimension.py @@ -1,8 +1,6 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2019, Frappe Technologies Pvt. Ltd. and contributors # For license information, please see license.txt -from __future__ import unicode_literals import json diff --git a/erpnext/accounts/doctype/accounting_dimension/test_accounting_dimension.py b/erpnext/accounts/doctype/accounting_dimension/test_accounting_dimension.py index 3769fc12707..f781a221ddf 100644 --- a/erpnext/accounts/doctype/accounting_dimension/test_accounting_dimension.py +++ b/erpnext/accounts/doctype/accounting_dimension/test_accounting_dimension.py @@ -1,7 +1,5 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2019, Frappe Technologies Pvt. Ltd. and Contributors # See license.txt -from __future__ import unicode_literals import unittest diff --git a/erpnext/accounts/doctype/accounting_dimension_detail/accounting_dimension_detail.py b/erpnext/accounts/doctype/accounting_dimension_detail/accounting_dimension_detail.py index c116f164536..4b0cbb35a0a 100644 --- a/erpnext/accounts/doctype/accounting_dimension_detail/accounting_dimension_detail.py +++ b/erpnext/accounts/doctype/accounting_dimension_detail/accounting_dimension_detail.py @@ -1,8 +1,6 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2019, Frappe Technologies Pvt. Ltd. and contributors # For license information, please see license.txt -from __future__ import unicode_literals # import frappe from frappe.model.document import Document diff --git a/erpnext/accounts/doctype/accounting_dimension_filter/accounting_dimension_filter.js b/erpnext/accounts/doctype/accounting_dimension_filter/accounting_dimension_filter.js index 9dd882a3119..750e129ba78 100644 --- a/erpnext/accounts/doctype/accounting_dimension_filter/accounting_dimension_filter.js +++ b/erpnext/accounts/doctype/accounting_dimension_filter/accounting_dimension_filter.js @@ -8,7 +8,7 @@ frappe.ui.form.on('Accounting Dimension Filter', { } let help_content = - ` + `
' - for cdf in child_meta.fields: - if cdf.in_list_view: - if create_head: - table_head += '' - if item.get(cdf.fieldname): - table_row += '' - else: - table_row += '' - create_head = False - table_row += '' - - html += "

diff --git a/erpnext/accounts/doctype/accounting_dimension_filter/accounting_dimension_filter.py b/erpnext/accounts/doctype/accounting_dimension_filter/accounting_dimension_filter.py index cb8c7d1c984..7d32bad0e78 100644 --- a/erpnext/accounts/doctype/accounting_dimension_filter/accounting_dimension_filter.py +++ b/erpnext/accounts/doctype/accounting_dimension_filter/accounting_dimension_filter.py @@ -1,8 +1,6 @@ -# -*- coding: utf-8 -*- # Copyright, (c) 2020, Frappe Technologies Pvt. Ltd. and contributors # For license information, please see license.txt -from __future__ import unicode_literals import frappe from frappe import _, scrub diff --git a/erpnext/accounts/doctype/accounting_dimension_filter/test_accounting_dimension_filter.py b/erpnext/accounts/doctype/accounting_dimension_filter/test_accounting_dimension_filter.py index 9968f689916..e2f85ba21a9 100644 --- a/erpnext/accounts/doctype/accounting_dimension_filter/test_accounting_dimension_filter.py +++ b/erpnext/accounts/doctype/accounting_dimension_filter/test_accounting_dimension_filter.py @@ -1,7 +1,5 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2020, Frappe Technologies Pvt. Ltd. and Contributors # See license.txt -from __future__ import unicode_literals import unittest diff --git a/erpnext/accounts/doctype/accounting_period/accounting_period.py b/erpnext/accounts/doctype/accounting_period/accounting_period.py index 67d1a8a09bd..e2949378e5f 100644 --- a/erpnext/accounts/doctype/accounting_period/accounting_period.py +++ b/erpnext/accounts/doctype/accounting_period/accounting_period.py @@ -1,8 +1,6 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2018, Frappe Technologies Pvt. Ltd. and contributors # For license information, please see license.txt -from __future__ import unicode_literals import frappe from frappe import _ diff --git a/erpnext/accounts/doctype/accounting_period/test_accounting_period.py b/erpnext/accounts/doctype/accounting_period/test_accounting_period.py index 5885b58e481..c06c2e0338b 100644 --- a/erpnext/accounts/doctype/accounting_period/test_accounting_period.py +++ b/erpnext/accounts/doctype/accounting_period/test_accounting_period.py @@ -1,7 +1,5 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2018, Frappe Technologies Pvt. Ltd. and Contributors # See license.txt -from __future__ import unicode_literals import unittest diff --git a/erpnext/accounts/doctype/accounts_settings/accounts_settings.json b/erpnext/accounts/doctype/accounts_settings/accounts_settings.json index 7d0ecfbafd9..55ea571ebf8 100644 --- a/erpnext/accounts/doctype/accounts_settings/accounts_settings.json +++ b/erpnext/accounts/doctype/accounts_settings/accounts_settings.json @@ -174,7 +174,7 @@ "default": "0", "fieldname": "automatically_fetch_payment_terms", "fieldtype": "Check", - "label": "Automatically Fetch Payment Terms" + "label": "Automatically Fetch Payment Terms from Order" }, { "description": "The percentage you are allowed to bill more against the amount ordered. For example, if the order value is $100 for an item and tolerance is set as 10%, then you are allowed to bill up to $110 ", @@ -282,7 +282,7 @@ "index_web_pages_for_search": 1, "issingle": 1, "links": [], - "modified": "2021-08-19 11:17:38.788054", + "modified": "2021-10-11 17:42:36.427699", "modified_by": "Administrator", "module": "Accounts", "name": "Accounts Settings", diff --git a/erpnext/accounts/doctype/accounts_settings/accounts_settings.py b/erpnext/accounts/doctype/accounts_settings/accounts_settings.py index f54473351a2..745191712b2 100644 --- a/erpnext/accounts/doctype/accounts_settings/accounts_settings.py +++ b/erpnext/accounts/doctype/accounts_settings/accounts_settings.py @@ -3,7 +3,6 @@ # For license information, please see license.txt -from __future__ import unicode_literals import frappe from frappe import _ @@ -20,6 +19,9 @@ class AccountsSettings(Document): frappe.db.set_default("add_taxes_from_item_tax_template", self.get("add_taxes_from_item_tax_template", 0)) + frappe.db.set_default("enable_common_party_accounting", + self.get("enable_common_party_accounting", 0)) + self.validate_stale_days() self.enable_payment_schedule_in_print() self.toggle_discount_accounting_fields() diff --git a/erpnext/accounts/doctype/accounts_settings/test_accounts_settings.py b/erpnext/accounts/doctype/accounts_settings/test_accounts_settings.py index c1c156fa65e..bf1e967bdbc 100644 --- a/erpnext/accounts/doctype/accounts_settings/test_accounts_settings.py +++ b/erpnext/accounts/doctype/accounts_settings/test_accounts_settings.py @@ -1,5 +1,3 @@ -from __future__ import unicode_literals - import unittest import frappe diff --git a/erpnext/accounts/doctype/advance_taxes_and_charges/advance_taxes_and_charges.py b/erpnext/accounts/doctype/advance_taxes_and_charges/advance_taxes_and_charges.py index 0c98f248746..55c84fb9e50 100644 --- a/erpnext/accounts/doctype/advance_taxes_and_charges/advance_taxes_and_charges.py +++ b/erpnext/accounts/doctype/advance_taxes_and_charges/advance_taxes_and_charges.py @@ -1,8 +1,6 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2020, Frappe Technologies Pvt. Ltd. and contributors # For license information, please see license.txt -from __future__ import unicode_literals # import frappe from frappe.model.document import Document diff --git a/erpnext/accounts/doctype/allowed_dimension/allowed_dimension.py b/erpnext/accounts/doctype/allowed_dimension/allowed_dimension.py index b5e7ad3fbe2..a3173a84f6c 100644 --- a/erpnext/accounts/doctype/allowed_dimension/allowed_dimension.py +++ b/erpnext/accounts/doctype/allowed_dimension/allowed_dimension.py @@ -1,8 +1,6 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2020, Frappe Technologies Pvt. Ltd. and contributors # For license information, please see license.txt -from __future__ import unicode_literals # import frappe from frappe.model.document import Document diff --git a/erpnext/accounts/doctype/allowed_to_transact_with/allowed_to_transact_with.py b/erpnext/accounts/doctype/allowed_to_transact_with/allowed_to_transact_with.py index 3e84c3071b0..a532070d1e4 100644 --- a/erpnext/accounts/doctype/allowed_to_transact_with/allowed_to_transact_with.py +++ b/erpnext/accounts/doctype/allowed_to_transact_with/allowed_to_transact_with.py @@ -1,8 +1,6 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2018, Frappe Technologies Pvt. Ltd. and contributors # For license information, please see license.txt -from __future__ import unicode_literals from frappe.model.document import Document diff --git a/erpnext/accounts/doctype/applicable_on_account/applicable_on_account.py b/erpnext/accounts/doctype/applicable_on_account/applicable_on_account.py index 91331fadd51..aae216627c6 100644 --- a/erpnext/accounts/doctype/applicable_on_account/applicable_on_account.py +++ b/erpnext/accounts/doctype/applicable_on_account/applicable_on_account.py @@ -1,8 +1,6 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2020, Frappe Technologies Pvt. Ltd. and contributors # For license information, please see license.txt -from __future__ import unicode_literals # import frappe from frappe.model.document import Document diff --git a/erpnext/accounts/doctype/bank/bank.py b/erpnext/accounts/doctype/bank/bank.py index e1eb984f5f5..f111433c321 100644 --- a/erpnext/accounts/doctype/bank/bank.py +++ b/erpnext/accounts/doctype/bank/bank.py @@ -1,8 +1,6 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2018, Frappe Technologies Pvt. Ltd. and contributors # For license information, please see license.txt -from __future__ import unicode_literals from frappe.contacts.address_and_contact import ( delete_contact_and_address, diff --git a/erpnext/accounts/doctype/bank/bank_dashboard.py b/erpnext/accounts/doctype/bank/bank_dashboard.py index 1e2383de5fd..36482aac960 100644 --- a/erpnext/accounts/doctype/bank/bank_dashboard.py +++ b/erpnext/accounts/doctype/bank/bank_dashboard.py @@ -1,5 +1,3 @@ -from __future__ import unicode_literals - from frappe import _ diff --git a/erpnext/accounts/doctype/bank/test_bank.py b/erpnext/accounts/doctype/bank/test_bank.py index 62d14d6fc63..5ca0e999bfb 100644 --- a/erpnext/accounts/doctype/bank/test_bank.py +++ b/erpnext/accounts/doctype/bank/test_bank.py @@ -1,7 +1,5 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2018, Frappe Technologies Pvt. Ltd. and Contributors # See license.txt -from __future__ import unicode_literals import unittest diff --git a/erpnext/accounts/doctype/bank_account/bank_account.py b/erpnext/accounts/doctype/bank_account/bank_account.py index 703f55de807..f9140c31d64 100644 --- a/erpnext/accounts/doctype/bank_account/bank_account.py +++ b/erpnext/accounts/doctype/bank_account/bank_account.py @@ -1,8 +1,6 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and contributors # For license information, please see license.txt -from __future__ import unicode_literals import frappe from frappe import _ diff --git a/erpnext/accounts/doctype/bank_account/bank_account_dashboard.py b/erpnext/accounts/doctype/bank_account/bank_account_dashboard.py index c7ea1522993..db4d7e51d59 100644 --- a/erpnext/accounts/doctype/bank_account/bank_account_dashboard.py +++ b/erpnext/accounts/doctype/bank_account/bank_account_dashboard.py @@ -1,5 +1,3 @@ -from __future__ import unicode_literals - from frappe import _ diff --git a/erpnext/accounts/doctype/bank_account/test_bank_account.py b/erpnext/accounts/doctype/bank_account/test_bank_account.py index dc970f3d99e..5f23f88af6c 100644 --- a/erpnext/accounts/doctype/bank_account/test_bank_account.py +++ b/erpnext/accounts/doctype/bank_account/test_bank_account.py @@ -1,7 +1,5 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors # See license.txt -from __future__ import unicode_literals import unittest diff --git a/erpnext/accounts/doctype/bank_account_subtype/bank_account_subtype.py b/erpnext/accounts/doctype/bank_account_subtype/bank_account_subtype.py index 84fa0c92b80..6355478fbde 100644 --- a/erpnext/accounts/doctype/bank_account_subtype/bank_account_subtype.py +++ b/erpnext/accounts/doctype/bank_account_subtype/bank_account_subtype.py @@ -1,8 +1,6 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2018, Frappe Technologies Pvt. Ltd. and contributors # For license information, please see license.txt -from __future__ import unicode_literals from frappe.model.document import Document diff --git a/erpnext/accounts/doctype/bank_account_subtype/test_bank_account_subtype.py b/erpnext/accounts/doctype/bank_account_subtype/test_bank_account_subtype.py index d4eb88b3656..a5faf1c2195 100644 --- a/erpnext/accounts/doctype/bank_account_subtype/test_bank_account_subtype.py +++ b/erpnext/accounts/doctype/bank_account_subtype/test_bank_account_subtype.py @@ -1,7 +1,5 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2018, Frappe Technologies Pvt. Ltd. and Contributors # See license.txt -from __future__ import unicode_literals import unittest diff --git a/erpnext/accounts/doctype/bank_account_type/bank_account_type.py b/erpnext/accounts/doctype/bank_account_type/bank_account_type.py index bba43dc486c..177b711166d 100644 --- a/erpnext/accounts/doctype/bank_account_type/bank_account_type.py +++ b/erpnext/accounts/doctype/bank_account_type/bank_account_type.py @@ -1,8 +1,6 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2020, Frappe Technologies Pvt. Ltd. and contributors # For license information, please see license.txt -from __future__ import unicode_literals # import frappe from frappe.model.document import Document diff --git a/erpnext/accounts/doctype/bank_account_type/test_bank_account_type.py b/erpnext/accounts/doctype/bank_account_type/test_bank_account_type.py index 00fd4338d22..fee8b47cdcb 100644 --- a/erpnext/accounts/doctype/bank_account_type/test_bank_account_type.py +++ b/erpnext/accounts/doctype/bank_account_type/test_bank_account_type.py @@ -1,7 +1,5 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2020, Frappe Technologies Pvt. Ltd. and Contributors # See license.txt -from __future__ import unicode_literals # import frappe import unittest diff --git a/erpnext/accounts/doctype/bank_clearance/bank_clearance.py b/erpnext/accounts/doctype/bank_clearance/bank_clearance.py index 340b4481785..a3bbb2288d3 100644 --- a/erpnext/accounts/doctype/bank_clearance/bank_clearance.py +++ b/erpnext/accounts/doctype/bank_clearance/bank_clearance.py @@ -1,7 +1,6 @@ # Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors # License: GNU General Public License v3. See license.txt -from __future__ import unicode_literals import frappe from frappe import _, msgprint diff --git a/erpnext/accounts/doctype/bank_clearance/test_bank_clearance.py b/erpnext/accounts/doctype/bank_clearance/test_bank_clearance.py index bdf3c7f48ae..706fbbe245c 100644 --- a/erpnext/accounts/doctype/bank_clearance/test_bank_clearance.py +++ b/erpnext/accounts/doctype/bank_clearance/test_bank_clearance.py @@ -1,7 +1,5 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2020, Frappe Technologies Pvt. Ltd. and Contributors # See license.txt -from __future__ import unicode_literals # import frappe import unittest diff --git a/erpnext/accounts/doctype/bank_clearance_detail/__init__.py b/erpnext/accounts/doctype/bank_clearance_detail/__init__.py index baffc488252..e69de29bb2d 100644 --- a/erpnext/accounts/doctype/bank_clearance_detail/__init__.py +++ b/erpnext/accounts/doctype/bank_clearance_detail/__init__.py @@ -1 +0,0 @@ -from __future__ import unicode_literals diff --git a/erpnext/accounts/doctype/bank_clearance_detail/bank_clearance_detail.py b/erpnext/accounts/doctype/bank_clearance_detail/bank_clearance_detail.py index 1b23400cd37..3d29fd7a484 100644 --- a/erpnext/accounts/doctype/bank_clearance_detail/bank_clearance_detail.py +++ b/erpnext/accounts/doctype/bank_clearance_detail/bank_clearance_detail.py @@ -1,7 +1,6 @@ # Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors # License: GNU General Public License v3. See license.txt -from __future__ import unicode_literals from frappe.model.document import Document diff --git a/erpnext/accounts/doctype/bank_guarantee/bank_guarantee.py b/erpnext/accounts/doctype/bank_guarantee/bank_guarantee.py index 8043c5f04e5..cfbcf16b91e 100644 --- a/erpnext/accounts/doctype/bank_guarantee/bank_guarantee.py +++ b/erpnext/accounts/doctype/bank_guarantee/bank_guarantee.py @@ -1,8 +1,6 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and contributors # For license information, please see license.txt -from __future__ import unicode_literals import json diff --git a/erpnext/accounts/doctype/bank_guarantee/test_bank_guarantee.py b/erpnext/accounts/doctype/bank_guarantee/test_bank_guarantee.py index 5cd455fd6c6..b992c6ad1db 100644 --- a/erpnext/accounts/doctype/bank_guarantee/test_bank_guarantee.py +++ b/erpnext/accounts/doctype/bank_guarantee/test_bank_guarantee.py @@ -1,7 +1,5 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2018, Frappe Technologies Pvt. Ltd. and Contributors # See license.txt -from __future__ import unicode_literals import unittest diff --git a/erpnext/accounts/doctype/bank_reconciliation_tool/bank_reconciliation_tool.py b/erpnext/accounts/doctype/bank_reconciliation_tool/bank_reconciliation_tool.py index ce64ee4f5a2..5cbf00b2c69 100644 --- a/erpnext/accounts/doctype/bank_reconciliation_tool/bank_reconciliation_tool.py +++ b/erpnext/accounts/doctype/bank_reconciliation_tool/bank_reconciliation_tool.py @@ -1,8 +1,6 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2020, Frappe Technologies Pvt. Ltd. and contributors # For license information, please see license.txt -from __future__ import unicode_literals import json @@ -344,7 +342,15 @@ def get_pe_matching_query(amount_condition, account_from_to, transaction): def get_je_matching_query(amount_condition, transaction): # get matching journal entry query - cr_or_dr = "credit" if transaction.withdrawal > 0 else "debit" + + company_account = frappe.get_value("Bank Account", transaction.bank_account, "account") + root_type = frappe.get_value("Account", company_account, "root_type") + + if root_type == "Liability": + cr_or_dr = "debit" if transaction.withdrawal > 0 else "credit" + else: + cr_or_dr = "credit" if transaction.withdrawal > 0 else "debit" + return f""" SELECT diff --git a/erpnext/accounts/doctype/bank_reconciliation_tool/test_bank_reconciliation_tool.py b/erpnext/accounts/doctype/bank_reconciliation_tool/test_bank_reconciliation_tool.py index 55b83b6bdfe..599ced59192 100644 --- a/erpnext/accounts/doctype/bank_reconciliation_tool/test_bank_reconciliation_tool.py +++ b/erpnext/accounts/doctype/bank_reconciliation_tool/test_bank_reconciliation_tool.py @@ -1,7 +1,5 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2020, Frappe Technologies Pvt. Ltd. and Contributors # See license.txt -from __future__ import unicode_literals # import frappe import unittest diff --git a/erpnext/accounts/doctype/bank_statement_import/bank_statement_import.py b/erpnext/accounts/doctype/bank_statement_import/bank_statement_import.py index 25d1023c270..e786d13c95d 100644 --- a/erpnext/accounts/doctype/bank_statement_import/bank_statement_import.py +++ b/erpnext/accounts/doctype/bank_statement_import/bank_statement_import.py @@ -1,8 +1,6 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2019, Frappe Technologies and contributors # For license information, please see license.txt -from __future__ import unicode_literals import csv import json @@ -17,7 +15,6 @@ from frappe.utils.background_jobs import enqueue from frappe.utils.xlsxutils import ILLEGAL_CHARACTERS_RE, handle_html from openpyxl.styles import Font from openpyxl.utils import get_column_letter -from six import string_types class BankStatementImport(DataImport): @@ -181,12 +178,12 @@ def write_xlsx(data, sheet_name, wb=None, column_widths=None, file_path=None): for row in data: clean_row = [] for item in row: - if isinstance(item, string_types) and (sheet_name not in ['Data Import Template', 'Data Export']): + if isinstance(item, str) and (sheet_name not in ['Data Import Template', 'Data Export']): value = handle_html(item) else: value = item - if isinstance(item, string_types) and next(ILLEGAL_CHARACTERS_RE.finditer(value), None): + if isinstance(item, str) and next(ILLEGAL_CHARACTERS_RE.finditer(value), None): # Remove illegal characters from the string value = re.sub(ILLEGAL_CHARACTERS_RE, '', value) diff --git a/erpnext/accounts/doctype/bank_statement_import/test_bank_statement_import.py b/erpnext/accounts/doctype/bank_statement_import/test_bank_statement_import.py index 5b45fa204bf..08c12bddb0b 100644 --- a/erpnext/accounts/doctype/bank_statement_import/test_bank_statement_import.py +++ b/erpnext/accounts/doctype/bank_statement_import/test_bank_statement_import.py @@ -1,7 +1,5 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2020, Frappe Technologies and Contributors # See license.txt -from __future__ import unicode_literals # import frappe import unittest diff --git a/erpnext/accounts/doctype/bank_transaction/bank_transaction.py b/erpnext/accounts/doctype/bank_transaction/bank_transaction.py index c4cf37e0c82..46200873044 100644 --- a/erpnext/accounts/doctype/bank_transaction/bank_transaction.py +++ b/erpnext/accounts/doctype/bank_transaction/bank_transaction.py @@ -1,8 +1,6 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2019, Frappe Technologies Pvt. Ltd. and contributors # For license information, please see license.txt -from __future__ import unicode_literals import frappe from frappe.utils import flt diff --git a/erpnext/accounts/doctype/bank_transaction/bank_transaction_upload.py b/erpnext/accounts/doctype/bank_transaction/bank_transaction_upload.py index e8d032be360..cca8a88c301 100644 --- a/erpnext/accounts/doctype/bank_transaction/bank_transaction_upload.py +++ b/erpnext/accounts/doctype/bank_transaction/bank_transaction_upload.py @@ -1,15 +1,12 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2018, Frappe Technologies Pvt. Ltd. and contributors # For license information, please see license.txt -from __future__ import unicode_literals import json import frappe from frappe.utils import getdate from frappe.utils.dateutils import parse_date -from six import iteritems @frappe.whitelist() @@ -45,7 +42,7 @@ def create_bank_entries(columns, data, bank_account): if all(item is None for item in d) is True: continue fields = {} - for key, value in iteritems(header_map): + for key, value in header_map.items(): fields.update({key: d[int(value)-1]}) try: diff --git a/erpnext/accounts/doctype/bank_transaction/test_bank_transaction.py b/erpnext/accounts/doctype/bank_transaction/test_bank_transaction.py index 35d08bd8033..72b6893faf5 100644 --- a/erpnext/accounts/doctype/bank_transaction/test_bank_transaction.py +++ b/erpnext/accounts/doctype/bank_transaction/test_bank_transaction.py @@ -1,7 +1,5 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2018, Frappe Technologies Pvt. Ltd. and Contributors # See license.txt -from __future__ import unicode_literals import json import unittest diff --git a/erpnext/accounts/doctype/bank_transaction_mapping/bank_transaction_mapping.py b/erpnext/accounts/doctype/bank_transaction_mapping/bank_transaction_mapping.py index 8b809fe705d..e19712ccff0 100644 --- a/erpnext/accounts/doctype/bank_transaction_mapping/bank_transaction_mapping.py +++ b/erpnext/accounts/doctype/bank_transaction_mapping/bank_transaction_mapping.py @@ -1,8 +1,6 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2018, Frappe Technologies Pvt. Ltd. and contributors # For license information, please see license.txt -from __future__ import unicode_literals from frappe.model.document import Document diff --git a/erpnext/accounts/doctype/bank_transaction_payments/bank_transaction_payments.py b/erpnext/accounts/doctype/bank_transaction_payments/bank_transaction_payments.py index 2546f27a46e..0536aa24b37 100644 --- a/erpnext/accounts/doctype/bank_transaction_payments/bank_transaction_payments.py +++ b/erpnext/accounts/doctype/bank_transaction_payments/bank_transaction_payments.py @@ -1,8 +1,6 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2018, Frappe Technologies Pvt. Ltd. and contributors # For license information, please see license.txt -from __future__ import unicode_literals from frappe.model.document import Document diff --git a/erpnext/accounts/doctype/budget/budget.py b/erpnext/accounts/doctype/budget/budget.py index 9c20e82f169..492bb365589 100644 --- a/erpnext/accounts/doctype/budget/budget.py +++ b/erpnext/accounts/doctype/budget/budget.py @@ -1,8 +1,6 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and contributors # For license information, please see license.txt -from __future__ import unicode_literals import frappe from frappe import _ diff --git a/erpnext/accounts/doctype/budget/test_budget.py b/erpnext/accounts/doctype/budget/test_budget.py index cc8220920e3..9a83a0aa9a6 100644 --- a/erpnext/accounts/doctype/budget/test_budget.py +++ b/erpnext/accounts/doctype/budget/test_budget.py @@ -1,7 +1,5 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors # See license.txt -from __future__ import unicode_literals import unittest diff --git a/erpnext/accounts/doctype/budget_account/budget_account.py b/erpnext/accounts/doctype/budget_account/budget_account.py index 454e47d7a1a..65bc95157bb 100644 --- a/erpnext/accounts/doctype/budget_account/budget_account.py +++ b/erpnext/accounts/doctype/budget_account/budget_account.py @@ -1,8 +1,6 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and contributors # For license information, please see license.txt -from __future__ import unicode_literals from frappe.model.document import Document diff --git a/erpnext/accounts/doctype/c_form/__init__.py b/erpnext/accounts/doctype/c_form/__init__.py index baffc488252..e69de29bb2d 100644 --- a/erpnext/accounts/doctype/c_form/__init__.py +++ b/erpnext/accounts/doctype/c_form/__init__.py @@ -1 +0,0 @@ -from __future__ import unicode_literals diff --git a/erpnext/accounts/doctype/c_form/c_form.py b/erpnext/accounts/doctype/c_form/c_form.py index b1ab6481597..61331d32d8e 100644 --- a/erpnext/accounts/doctype/c_form/c_form.py +++ b/erpnext/accounts/doctype/c_form/c_form.py @@ -1,7 +1,6 @@ # Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors # License: GNU General Public License v3. See license.txt -from __future__ import unicode_literals import frappe from frappe import _ diff --git a/erpnext/accounts/doctype/c_form/test_c_form.py b/erpnext/accounts/doctype/c_form/test_c_form.py index e5c56157318..fa34c255c66 100644 --- a/erpnext/accounts/doctype/c_form/test_c_form.py +++ b/erpnext/accounts/doctype/c_form/test_c_form.py @@ -1,7 +1,5 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors # See license.txt -from __future__ import unicode_literals import unittest diff --git a/erpnext/accounts/doctype/c_form_invoice_detail/__init__.py b/erpnext/accounts/doctype/c_form_invoice_detail/__init__.py index baffc488252..e69de29bb2d 100644 --- a/erpnext/accounts/doctype/c_form_invoice_detail/__init__.py +++ b/erpnext/accounts/doctype/c_form_invoice_detail/__init__.py @@ -1 +0,0 @@ -from __future__ import unicode_literals diff --git a/erpnext/accounts/doctype/c_form_invoice_detail/c_form_invoice_detail.py b/erpnext/accounts/doctype/c_form_invoice_detail/c_form_invoice_detail.py index 1316227df91..1e6ab979782 100644 --- a/erpnext/accounts/doctype/c_form_invoice_detail/c_form_invoice_detail.py +++ b/erpnext/accounts/doctype/c_form_invoice_detail/c_form_invoice_detail.py @@ -1,7 +1,6 @@ # Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors # License: GNU General Public License v3. See license.txt -from __future__ import unicode_literals from frappe.model.document import Document diff --git a/erpnext/accounts/doctype/cash_flow_mapper/cash_flow_mapper.py b/erpnext/accounts/doctype/cash_flow_mapper/cash_flow_mapper.py index 96920b329e7..d975f803a0c 100644 --- a/erpnext/accounts/doctype/cash_flow_mapper/cash_flow_mapper.py +++ b/erpnext/accounts/doctype/cash_flow_mapper/cash_flow_mapper.py @@ -1,8 +1,6 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2018, Frappe Technologies Pvt. Ltd. and contributors # For license information, please see license.txt -from __future__ import unicode_literals from frappe.model.document import Document diff --git a/erpnext/accounts/doctype/cash_flow_mapper/default_cash_flow_mapper.py b/erpnext/accounts/doctype/cash_flow_mapper/default_cash_flow_mapper.py index 43ebcb0cac9..6e7b687c04d 100644 --- a/erpnext/accounts/doctype/cash_flow_mapper/default_cash_flow_mapper.py +++ b/erpnext/accounts/doctype/cash_flow_mapper/default_cash_flow_mapper.py @@ -1,5 +1,3 @@ -from __future__ import unicode_literals - DEFAULT_MAPPERS = [ { 'doctype': 'Cash Flow Mapper', diff --git a/erpnext/accounts/doctype/cash_flow_mapper/test_cash_flow_mapper.py b/erpnext/accounts/doctype/cash_flow_mapper/test_cash_flow_mapper.py index f055e563adb..044f2aee720 100644 --- a/erpnext/accounts/doctype/cash_flow_mapper/test_cash_flow_mapper.py +++ b/erpnext/accounts/doctype/cash_flow_mapper/test_cash_flow_mapper.py @@ -1,7 +1,5 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2018, Frappe Technologies Pvt. Ltd. and Contributors # See license.txt -from __future__ import unicode_literals import unittest diff --git a/erpnext/accounts/doctype/cash_flow_mapping/cash_flow_mapping.py b/erpnext/accounts/doctype/cash_flow_mapping/cash_flow_mapping.py index 9ec466a7a6d..cd8381a4bd3 100644 --- a/erpnext/accounts/doctype/cash_flow_mapping/cash_flow_mapping.py +++ b/erpnext/accounts/doctype/cash_flow_mapping/cash_flow_mapping.py @@ -1,8 +1,6 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2018, Frappe Technologies Pvt. Ltd. and contributors # For license information, please see license.txt -from __future__ import unicode_literals import frappe from frappe.model.document import Document diff --git a/erpnext/accounts/doctype/cash_flow_mapping/test_cash_flow_mapping.py b/erpnext/accounts/doctype/cash_flow_mapping/test_cash_flow_mapping.py index 5e44c61379b..abb25670467 100644 --- a/erpnext/accounts/doctype/cash_flow_mapping/test_cash_flow_mapping.py +++ b/erpnext/accounts/doctype/cash_flow_mapping/test_cash_flow_mapping.py @@ -1,7 +1,5 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2018, Frappe Technologies Pvt. Ltd. and Contributors # See license.txt -from __future__ import unicode_literals import unittest diff --git a/erpnext/accounts/doctype/cash_flow_mapping_accounts/cash_flow_mapping_accounts.py b/erpnext/accounts/doctype/cash_flow_mapping_accounts/cash_flow_mapping_accounts.py index 51740353192..d8dd05ce1c7 100644 --- a/erpnext/accounts/doctype/cash_flow_mapping_accounts/cash_flow_mapping_accounts.py +++ b/erpnext/accounts/doctype/cash_flow_mapping_accounts/cash_flow_mapping_accounts.py @@ -1,8 +1,6 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2018, Frappe Technologies Pvt. Ltd. and contributors # For license information, please see license.txt -from __future__ import unicode_literals from frappe.model.document import Document diff --git a/erpnext/accounts/doctype/cash_flow_mapping_template/cash_flow_mapping_template.py b/erpnext/accounts/doctype/cash_flow_mapping_template/cash_flow_mapping_template.py index fabf5796bcf..610428cf51f 100644 --- a/erpnext/accounts/doctype/cash_flow_mapping_template/cash_flow_mapping_template.py +++ b/erpnext/accounts/doctype/cash_flow_mapping_template/cash_flow_mapping_template.py @@ -1,8 +1,6 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2018, Frappe Technologies Pvt. Ltd. and contributors # For license information, please see license.txt -from __future__ import unicode_literals from frappe.model.document import Document diff --git a/erpnext/accounts/doctype/cash_flow_mapping_template/test_cash_flow_mapping_template.py b/erpnext/accounts/doctype/cash_flow_mapping_template/test_cash_flow_mapping_template.py index d6b964bb177..19461467359 100644 --- a/erpnext/accounts/doctype/cash_flow_mapping_template/test_cash_flow_mapping_template.py +++ b/erpnext/accounts/doctype/cash_flow_mapping_template/test_cash_flow_mapping_template.py @@ -1,7 +1,5 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2018, Frappe Technologies Pvt. Ltd. and Contributors # See license.txt -from __future__ import unicode_literals import unittest diff --git a/erpnext/accounts/doctype/cash_flow_mapping_template_details/cash_flow_mapping_template_details.py b/erpnext/accounts/doctype/cash_flow_mapping_template_details/cash_flow_mapping_template_details.py index f0ff33fb38f..d15ab7e802d 100644 --- a/erpnext/accounts/doctype/cash_flow_mapping_template_details/cash_flow_mapping_template_details.py +++ b/erpnext/accounts/doctype/cash_flow_mapping_template_details/cash_flow_mapping_template_details.py @@ -1,8 +1,6 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2018, Frappe Technologies Pvt. Ltd. and contributors # For license information, please see license.txt -from __future__ import unicode_literals from frappe.model.document import Document diff --git a/erpnext/accounts/doctype/cash_flow_mapping_template_details/test_cash_flow_mapping_template_details.py b/erpnext/accounts/doctype/cash_flow_mapping_template_details/test_cash_flow_mapping_template_details.py index db5683a5a74..5795e61aedd 100644 --- a/erpnext/accounts/doctype/cash_flow_mapping_template_details/test_cash_flow_mapping_template_details.py +++ b/erpnext/accounts/doctype/cash_flow_mapping_template_details/test_cash_flow_mapping_template_details.py @@ -1,7 +1,5 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2018, Frappe Technologies Pvt. Ltd. and Contributors # See license.txt -from __future__ import unicode_literals import unittest diff --git a/erpnext/accounts/doctype/cashier_closing/cashier_closing.py b/erpnext/accounts/doctype/cashier_closing/cashier_closing.py index cab7d407b54..9fbd0c97c1e 100644 --- a/erpnext/accounts/doctype/cashier_closing/cashier_closing.py +++ b/erpnext/accounts/doctype/cashier_closing/cashier_closing.py @@ -1,8 +1,6 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors # License: GNU General Public License v3. See license.txt -from __future__ import unicode_literals import frappe from frappe import _ diff --git a/erpnext/accounts/doctype/cashier_closing/test_cashier_closing.py b/erpnext/accounts/doctype/cashier_closing/test_cashier_closing.py index 981093f3d04..d11737c33cc 100644 --- a/erpnext/accounts/doctype/cashier_closing/test_cashier_closing.py +++ b/erpnext/accounts/doctype/cashier_closing/test_cashier_closing.py @@ -1,7 +1,5 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors # See license.txt -from __future__ import unicode_literals import unittest diff --git a/erpnext/accounts/doctype/cashier_closing_payments/cashier_closing_payments.py b/erpnext/accounts/doctype/cashier_closing_payments/cashier_closing_payments.py index a2a8b9437e4..7617f9bdba9 100644 --- a/erpnext/accounts/doctype/cashier_closing_payments/cashier_closing_payments.py +++ b/erpnext/accounts/doctype/cashier_closing_payments/cashier_closing_payments.py @@ -1,8 +1,6 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors # License: GNU General Public License v3. See license.txt -from __future__ import unicode_literals from frappe.model.document import Document diff --git a/erpnext/accounts/doctype/chart_of_accounts_importer/chart_of_accounts_importer.js b/erpnext/accounts/doctype/chart_of_accounts_importer/chart_of_accounts_importer.js index f795dfa83e6..d61f8a6c01c 100644 --- a/erpnext/accounts/doctype/chart_of_accounts_importer/chart_of_accounts_importer.js +++ b/erpnext/accounts/doctype/chart_of_accounts_importer/chart_of_accounts_importer.js @@ -10,13 +10,17 @@ frappe.ui.form.on('Chart of Accounts Importer', { // make company mandatory frm.set_df_property('company', 'reqd', frm.doc.company ? 0 : 1); frm.set_df_property('import_file_section', 'hidden', frm.doc.company ? 0 : 1); + + if (frm.doc.import_file) { + frappe.run_serially([ + () => generate_tree_preview(frm), + () => create_import_button(frm), + () => frm.set_df_property('chart_preview', 'hidden', 0) + ]); + } + frm.set_df_property('chart_preview', 'hidden', $(frm.fields_dict['chart_tree'].wrapper).html()!="" ? 0 : 1); - - // Show import button when file is successfully attached - if (frm.page && frm.page.show_import_button) { - create_import_button(frm); - } }, download_template: function(frm) { @@ -77,9 +81,6 @@ frappe.ui.form.on('Chart of Accounts Importer', { if (!frm.doc.import_file) { frm.page.set_indicator(""); $(frm.fields_dict['chart_tree'].wrapper).empty(); // empty wrapper on removing file - } else { - generate_tree_preview(frm); - validate_csv_data(frm); } }, @@ -104,26 +105,9 @@ frappe.ui.form.on('Chart of Accounts Importer', { } }); -var validate_csv_data = function(frm) { - frappe.call({ - method: "erpnext.accounts.doctype.chart_of_accounts_importer.chart_of_accounts_importer.validate_accounts", - args: {file_name: frm.doc.import_file}, - callback: function(r) { - if(r.message && r.message[0]===true) { - frm.page["show_import_button"] = true; - frm.page["total_accounts"] = r.message[1]; - frm.trigger("refresh"); - } else { - frm.page.set_indicator(__('Resolve error and upload again.'), 'orange'); - frappe.throw(__(r.message)); - } - } - }); -}; - var create_import_button = function(frm) { frm.page.set_primary_action(__("Import"), function () { - frappe.call({ + return frappe.call({ method: "erpnext.accounts.doctype.chart_of_accounts_importer.chart_of_accounts_importer.import_coa", args: { file_name: frm.doc.import_file, @@ -132,7 +116,7 @@ var create_import_button = function(frm) { freeze: true, freeze_message: __("Creating Accounts..."), callback: function(r) { - if(!r.exc) { + if (!r.exc) { clearInterval(frm.page["interval"]); frm.page.set_indicator(__('Import Successful'), 'blue'); create_reset_button(frm); @@ -150,12 +134,33 @@ var create_reset_button = function(frm) { }).addClass('btn btn-primary'); }; +var validate_coa = function(frm) { + if (frm.doc.import_file) { + let parent = __('All Accounts'); + return frappe.call({ + 'method': 'erpnext.accounts.doctype.chart_of_accounts_importer.chart_of_accounts_importer.get_coa', + 'args': { + file_name: frm.doc.import_file, + parent: parent, + doctype: 'Chart of Accounts Importer', + file_type: frm.doc.file_type, + for_validate: 1 + }, + callback: function(r) { + if (r.message['show_import_button']) { + frm.page['show_import_button'] = Boolean(r.message['show_import_button']); + } + } + }); + } +}; + var generate_tree_preview = function(frm) { let parent = __('All Accounts'); $(frm.fields_dict['chart_tree'].wrapper).empty(); // empty wrapper to load new data // generate tree structure based on the csv data - new frappe.ui.Tree({ + return new frappe.ui.Tree({ parent: $(frm.fields_dict['chart_tree'].wrapper), label: parent, expandable: true, diff --git a/erpnext/accounts/doctype/chart_of_accounts_importer/chart_of_accounts_importer.py b/erpnext/accounts/doctype/chart_of_accounts_importer/chart_of_accounts_importer.py index 61968cf627d..aaacce4eb9d 100644 --- a/erpnext/accounts/doctype/chart_of_accounts_importer/chart_of_accounts_importer.py +++ b/erpnext/accounts/doctype/chart_of_accounts_importer/chart_of_accounts_importer.py @@ -1,8 +1,6 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2019, Frappe Technologies Pvt. Ltd. and contributors # For license information, please see license.txt -from __future__ import unicode_literals import csv import os @@ -26,7 +24,18 @@ from erpnext.accounts.doctype.account.chart_of_accounts.chart_of_accounts import class ChartofAccountsImporter(Document): def validate(self): - validate_accounts(self.import_file) + if self.import_file: + get_coa('Chart of Accounts Importer', 'All Accounts', file_name=self.import_file, for_validate=1) + +def validate_columns(data): + if not data: + frappe.throw(_('No data found. Seems like you uploaded a blank file')) + + no_of_columns = max([len(d) for d in data]) + + if no_of_columns > 7: + frappe.throw(_('More columns found than expected. Please compare the uploaded file with standard template'), + title=(_("Wrong Template"))) @frappe.whitelist() def validate_company(company): @@ -56,8 +65,9 @@ def import_coa(file_name, company): else: data = generate_data_from_excel(file_doc, extension) + frappe.local.flags.ignore_root_company_validation = True forest = build_forest(data) - create_charts(company, custom_chart=forest) + create_charts(company, custom_chart=forest, from_coa_importer=True) # trigger on_update for company to reset default accounts set_default_accounts(company) @@ -120,7 +130,7 @@ def generate_data_from_excel(file_doc, extension, as_dict=False): return data @frappe.whitelist() -def get_coa(doctype, parent, is_root=False, file_name=None): +def get_coa(doctype, parent, is_root=False, file_name=None, for_validate=0): ''' called by tree view (to fetch node's children) ''' file_doc, extension = get_file(file_name) @@ -131,13 +141,21 @@ def get_coa(doctype, parent, is_root=False, file_name=None): else: data = generate_data_from_excel(file_doc, extension) - forest = build_forest(data) - accounts = build_tree_from_json("", chart_data=forest) # returns alist of dict in a tree render-able form + validate_columns(data) + validate_accounts(file_doc, extension) - # filter out to show data for the selected node only - accounts = [d for d in accounts if d['parent_account']==parent] + if not for_validate: + forest = build_forest(data) + accounts = build_tree_from_json("", chart_data=forest, from_coa_importer=True) # returns a list of dict in a tree render-able form - return accounts + # filter out to show data for the selected node only + accounts = [d for d in accounts if d['parent_account']==parent] + + return accounts + else: + return { + 'show_import_button': 1 + } def build_forest(data): ''' @@ -192,11 +210,14 @@ def build_forest(data): if not account_name: error_messages.append("Row {0}: Please enter Account Name".format(line_no)) + name = account_name if account_number: account_number = cstr(account_number).strip() account_name = "{} - {}".format(account_number, account_name) charts_map[account_name] = {} + charts_map[account_name]['account_name'] = name + if account_number: charts_map[account_name]["account_number"] = account_number if cint(is_group) == 1: charts_map[account_name]["is_group"] = is_group if account_type: charts_map[account_name]["account_type"] = account_type if root_type: charts_map[account_name]["root_type"] = root_type @@ -294,10 +315,7 @@ def get_sample_template(writer): @frappe.whitelist() -def validate_accounts(file_name): - - file_doc, extension = get_file(file_name) - +def validate_accounts(file_doc, extension): if extension == 'csv': accounts = generate_data_from_csv(file_doc, as_dict=True) else: @@ -316,15 +334,10 @@ def validate_accounts(file_name): validate_root(accounts_dict) - validate_account_types(accounts_dict) - return [True, len(accounts)] def validate_root(accounts): roots = [accounts[d] for d in accounts if not accounts[d].get('parent_account')] - if len(roots) < 4: - frappe.throw(_("Number of root accounts cannot be less than 4")) - error_messages = [] for account in roots: @@ -333,9 +346,19 @@ def validate_root(accounts): elif account.get("root_type") not in get_root_types() and account.get("account_name"): error_messages.append(_("Root Type for {0} must be one of the Asset, Liability, Income, Expense and Equity").format(account.get("account_name"))) + validate_missing_roots(roots) + if error_messages: frappe.throw("
".join(error_messages)) +def validate_missing_roots(roots): + root_types_added = set(d.get('root_type') for d in roots) + + missing = list(set(get_root_types()) - root_types_added) + + if missing: + frappe.throw(_("Please add Root Account for - {0}").format(' , '.join(missing))) + def get_root_types(): return ('Asset', 'Liability', 'Expense', 'Income', 'Equity') @@ -361,23 +384,6 @@ def get_mandatory_account_types(): {'account_type': 'Stock', 'root_type': 'Asset'} ] - -def validate_account_types(accounts): - account_types_for_ledger = ["Cost of Goods Sold", "Depreciation", "Fixed Asset", "Payable", "Receivable", "Stock Adjustment"] - account_types = [accounts[d]["account_type"] for d in accounts if not accounts[d]['is_group'] == 1] - - missing = list(set(account_types_for_ledger) - set(account_types)) - if missing: - frappe.throw(_("Please identify/create Account (Ledger) for type - {0}").format(' , '.join(missing))) - - account_types_for_group = ["Bank", "Cash", "Stock"] - # fix logic bug - account_groups = [accounts[d]["account_type"] for d in accounts if accounts[d]['is_group'] == 1] - - missing = list(set(account_types_for_group) - set(account_groups)) - if missing: - frappe.throw(_("Please identify/create Account (Group) for type - {0}").format(' , '.join(missing))) - def unset_existing_data(company): linked = frappe.db.sql('''select fieldname from tabDocField where fieldtype="Link" and options="Account" and parent="Company"''', as_dict=True) diff --git a/erpnext/accounts/doctype/chart_of_accounts_importer/test_chart_of_accounts_importer.py b/erpnext/accounts/doctype/chart_of_accounts_importer/test_chart_of_accounts_importer.py index ca9cf699aa7..00e5cc30671 100644 --- a/erpnext/accounts/doctype/chart_of_accounts_importer/test_chart_of_accounts_importer.py +++ b/erpnext/accounts/doctype/chart_of_accounts_importer/test_chart_of_accounts_importer.py @@ -1,7 +1,5 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2019, Frappe Technologies Pvt. Ltd. and Contributors # See license.txt -from __future__ import unicode_literals import unittest diff --git a/erpnext/accounts/doctype/cheque_print_template/cheque_print_template.py b/erpnext/accounts/doctype/cheque_print_template/cheque_print_template.py index 0f595ba933a..20cb42c109c 100644 --- a/erpnext/accounts/doctype/cheque_print_template/cheque_print_template.py +++ b/erpnext/accounts/doctype/cheque_print_template/cheque_print_template.py @@ -1,8 +1,6 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and contributors # For license information, please see license.txt -from __future__ import unicode_literals import frappe from frappe import _ diff --git a/erpnext/accounts/doctype/cheque_print_template/test_cheque_print_template.py b/erpnext/accounts/doctype/cheque_print_template/test_cheque_print_template.py index 8ce8794cfcf..2b323a9bf62 100644 --- a/erpnext/accounts/doctype/cheque_print_template/test_cheque_print_template.py +++ b/erpnext/accounts/doctype/cheque_print_template/test_cheque_print_template.py @@ -1,7 +1,5 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors # See license.txt -from __future__ import unicode_literals import unittest diff --git a/erpnext/accounts/doctype/closed_document/closed_document.py b/erpnext/accounts/doctype/closed_document/closed_document.py index 50469bc19c6..89d3d2e29c8 100644 --- a/erpnext/accounts/doctype/closed_document/closed_document.py +++ b/erpnext/accounts/doctype/closed_document/closed_document.py @@ -1,8 +1,6 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2018, Frappe Technologies Pvt. Ltd. and contributors # For license information, please see license.txt -from __future__ import unicode_literals from frappe.model.document import Document diff --git a/erpnext/accounts/doctype/cost_center/__init__.py b/erpnext/accounts/doctype/cost_center/__init__.py index baffc488252..e69de29bb2d 100644 --- a/erpnext/accounts/doctype/cost_center/__init__.py +++ b/erpnext/accounts/doctype/cost_center/__init__.py @@ -1 +0,0 @@ -from __future__ import unicode_literals diff --git a/erpnext/accounts/doctype/cost_center/cost_center.py b/erpnext/accounts/doctype/cost_center/cost_center.py index 166ebb83ac2..7ae0a72e3d1 100644 --- a/erpnext/accounts/doctype/cost_center/cost_center.py +++ b/erpnext/accounts/doctype/cost_center/cost_center.py @@ -1,7 +1,6 @@ # Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors # License: GNU General Public License v3. See license.txt -from __future__ import unicode_literals import frappe from frappe import _ diff --git a/erpnext/accounts/doctype/cost_center/cost_center_dashboard.py b/erpnext/accounts/doctype/cost_center/cost_center_dashboard.py index 24cf3ea0689..f524803f64c 100644 --- a/erpnext/accounts/doctype/cost_center/cost_center_dashboard.py +++ b/erpnext/accounts/doctype/cost_center/cost_center_dashboard.py @@ -1,5 +1,3 @@ -from __future__ import unicode_literals - from frappe import _ diff --git a/erpnext/accounts/doctype/cost_center/test_cost_center.py b/erpnext/accounts/doctype/cost_center/test_cost_center.py index 142b925c2ea..f8615ec03a5 100644 --- a/erpnext/accounts/doctype/cost_center/test_cost_center.py +++ b/erpnext/accounts/doctype/cost_center/test_cost_center.py @@ -1,6 +1,5 @@ # Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors # License: GNU General Public License v3. See license.txt -from __future__ import unicode_literals import unittest diff --git a/erpnext/accounts/doctype/coupon_code/coupon_code.py b/erpnext/accounts/doctype/coupon_code/coupon_code.py index bb2615b3610..ee32de1cd28 100644 --- a/erpnext/accounts/doctype/coupon_code/coupon_code.py +++ b/erpnext/accounts/doctype/coupon_code/coupon_code.py @@ -1,8 +1,6 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2018, Frappe Technologies Pvt. Ltd. and contributors # For license information, please see license.txt -from __future__ import unicode_literals import frappe from frappe import _ diff --git a/erpnext/accounts/doctype/coupon_code/test_coupon_code.py b/erpnext/accounts/doctype/coupon_code/test_coupon_code.py index bf8c014a5b9..5ba06913310 100644 --- a/erpnext/accounts/doctype/coupon_code/test_coupon_code.py +++ b/erpnext/accounts/doctype/coupon_code/test_coupon_code.py @@ -1,7 +1,5 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2018, Frappe Technologies Pvt. Ltd. and Contributors # See license.txt -from __future__ import unicode_literals import unittest diff --git a/erpnext/accounts/doctype/discounted_invoice/discounted_invoice.py b/erpnext/accounts/doctype/discounted_invoice/discounted_invoice.py index 11faa773c65..9b8932c19e0 100644 --- a/erpnext/accounts/doctype/discounted_invoice/discounted_invoice.py +++ b/erpnext/accounts/doctype/discounted_invoice/discounted_invoice.py @@ -1,8 +1,6 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2019, Frappe Technologies Pvt. Ltd. and contributors # For license information, please see license.txt -from __future__ import unicode_literals # import frappe from frappe.model.document import Document diff --git a/erpnext/accounts/doctype/distributed_cost_center/distributed_cost_center.py b/erpnext/accounts/doctype/distributed_cost_center/distributed_cost_center.py index 436704008ea..dcf0e3b99de 100644 --- a/erpnext/accounts/doctype/distributed_cost_center/distributed_cost_center.py +++ b/erpnext/accounts/doctype/distributed_cost_center/distributed_cost_center.py @@ -1,8 +1,6 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2020, Frappe Technologies Pvt. Ltd. and contributors # For license information, please see license.txt -from __future__ import unicode_literals # import frappe from frappe.model.document import Document diff --git a/erpnext/accounts/doctype/dunning/dunning.py b/erpnext/accounts/doctype/dunning/dunning.py index 65ada530df5..5da0077a2be 100644 --- a/erpnext/accounts/doctype/dunning/dunning.py +++ b/erpnext/accounts/doctype/dunning/dunning.py @@ -1,14 +1,11 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2020, Frappe Technologies Pvt. Ltd. and contributors # For license information, please see license.txt -from __future__ import unicode_literals import json import frappe from frappe.utils import cint, flt, getdate -from six import string_types from erpnext.accounts.doctype.accounting_dimension.accounting_dimension import ( get_accounting_dimensions, @@ -110,7 +107,7 @@ def calculate_interest_and_amount(outstanding_amount, rate_of_interest, dunning_ @frappe.whitelist() def get_dunning_letter_text(dunning_type, doc, language=None): - if isinstance(doc, string_types): + if isinstance(doc, str): doc = json.loads(doc) if language: filters = {'parent': dunning_type, 'language': language} diff --git a/erpnext/accounts/doctype/dunning/dunning_dashboard.py b/erpnext/accounts/doctype/dunning/dunning_dashboard.py index fa3330f7cfd..a891bd29171 100644 --- a/erpnext/accounts/doctype/dunning/dunning_dashboard.py +++ b/erpnext/accounts/doctype/dunning/dunning_dashboard.py @@ -1,5 +1,3 @@ -from __future__ import unicode_literals - from frappe import _ diff --git a/erpnext/accounts/doctype/dunning/test_dunning.py b/erpnext/accounts/doctype/dunning/test_dunning.py index 9e8b6553360..b043c5ba19c 100644 --- a/erpnext/accounts/doctype/dunning/test_dunning.py +++ b/erpnext/accounts/doctype/dunning/test_dunning.py @@ -1,7 +1,5 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2020, Frappe Technologies Pvt. Ltd. and Contributors # See license.txt -from __future__ import unicode_literals import unittest diff --git a/erpnext/accounts/doctype/dunning_letter_text/dunning_letter_text.py b/erpnext/accounts/doctype/dunning_letter_text/dunning_letter_text.py index b14fdc11f2a..9f3cf7f3f6c 100644 --- a/erpnext/accounts/doctype/dunning_letter_text/dunning_letter_text.py +++ b/erpnext/accounts/doctype/dunning_letter_text/dunning_letter_text.py @@ -1,8 +1,6 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2020, Frappe Technologies Pvt. Ltd. and contributors # For license information, please see license.txt -from __future__ import unicode_literals # import frappe from frappe.model.document import Document diff --git a/erpnext/accounts/doctype/dunning_type/dunning_type.py b/erpnext/accounts/doctype/dunning_type/dunning_type.py index 64e7cf420fe..1b9bb9c0325 100644 --- a/erpnext/accounts/doctype/dunning_type/dunning_type.py +++ b/erpnext/accounts/doctype/dunning_type/dunning_type.py @@ -1,8 +1,6 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2020, Frappe Technologies Pvt. Ltd. and contributors # For license information, please see license.txt -from __future__ import unicode_literals # import frappe from frappe.model.document import Document diff --git a/erpnext/accounts/doctype/dunning_type/test_dunning_type.py b/erpnext/accounts/doctype/dunning_type/test_dunning_type.py index ae08907273e..67b72e4be75 100644 --- a/erpnext/accounts/doctype/dunning_type/test_dunning_type.py +++ b/erpnext/accounts/doctype/dunning_type/test_dunning_type.py @@ -1,7 +1,5 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2020, Frappe Technologies Pvt. Ltd. and Contributors # See license.txt -from __future__ import unicode_literals # import frappe import unittest diff --git a/erpnext/accounts/doctype/exchange_rate_revaluation/exchange_rate_revaluation.py b/erpnext/accounts/doctype/exchange_rate_revaluation/exchange_rate_revaluation.py index 9c173d0c517..1b13195ce98 100644 --- a/erpnext/accounts/doctype/exchange_rate_revaluation/exchange_rate_revaluation.py +++ b/erpnext/accounts/doctype/exchange_rate_revaluation/exchange_rate_revaluation.py @@ -1,8 +1,6 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2018, Frappe Technologies Pvt. Ltd. and contributors # For license information, please see license.txt -from __future__ import unicode_literals import frappe from frappe import _ diff --git a/erpnext/accounts/doctype/exchange_rate_revaluation/exchange_rate_revaluation_dashboard.py b/erpnext/accounts/doctype/exchange_rate_revaluation/exchange_rate_revaluation_dashboard.py index 7358f561ed4..fe862507fb8 100644 --- a/erpnext/accounts/doctype/exchange_rate_revaluation/exchange_rate_revaluation_dashboard.py +++ b/erpnext/accounts/doctype/exchange_rate_revaluation/exchange_rate_revaluation_dashboard.py @@ -1,6 +1,3 @@ -from __future__ import unicode_literals - - def get_data(): return { 'fieldname': 'reference_name', diff --git a/erpnext/accounts/doctype/exchange_rate_revaluation/test_exchange_rate_revaluation.py b/erpnext/accounts/doctype/exchange_rate_revaluation/test_exchange_rate_revaluation.py index e725ce4da45..ec55e60fd1f 100644 --- a/erpnext/accounts/doctype/exchange_rate_revaluation/test_exchange_rate_revaluation.py +++ b/erpnext/accounts/doctype/exchange_rate_revaluation/test_exchange_rate_revaluation.py @@ -1,7 +1,5 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2018, Frappe Technologies Pvt. Ltd. and Contributors # See license.txt -from __future__ import unicode_literals import unittest diff --git a/erpnext/accounts/doctype/exchange_rate_revaluation_account/exchange_rate_revaluation_account.py b/erpnext/accounts/doctype/exchange_rate_revaluation_account/exchange_rate_revaluation_account.py index 58375dd4ef9..96a92bb31fd 100644 --- a/erpnext/accounts/doctype/exchange_rate_revaluation_account/exchange_rate_revaluation_account.py +++ b/erpnext/accounts/doctype/exchange_rate_revaluation_account/exchange_rate_revaluation_account.py @@ -1,8 +1,6 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2018, Frappe Technologies Pvt. Ltd. and contributors # For license information, please see license.txt -from __future__ import unicode_literals from frappe.model.document import Document diff --git a/erpnext/accounts/doctype/finance_book/finance_book.py b/erpnext/accounts/doctype/finance_book/finance_book.py index 527b8e67886..78b321b2da4 100644 --- a/erpnext/accounts/doctype/finance_book/finance_book.py +++ b/erpnext/accounts/doctype/finance_book/finance_book.py @@ -1,8 +1,6 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2018, Frappe Technologies Pvt. Ltd. and contributors # For license information, please see license.txt -from __future__ import unicode_literals from frappe.model.document import Document diff --git a/erpnext/accounts/doctype/finance_book/finance_book_dashboard.py b/erpnext/accounts/doctype/finance_book/finance_book_dashboard.py index c2ebea6e8f8..57b039d022b 100644 --- a/erpnext/accounts/doctype/finance_book/finance_book_dashboard.py +++ b/erpnext/accounts/doctype/finance_book/finance_book_dashboard.py @@ -1,5 +1,3 @@ -from __future__ import unicode_literals - from frappe import _ diff --git a/erpnext/accounts/doctype/finance_book/test_finance_book.py b/erpnext/accounts/doctype/finance_book/test_finance_book.py index 87a8ae260c0..5fb3d0a96cb 100644 --- a/erpnext/accounts/doctype/finance_book/test_finance_book.py +++ b/erpnext/accounts/doctype/finance_book/test_finance_book.py @@ -1,7 +1,5 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2018, Frappe Technologies Pvt. Ltd. and Contributors # See license.txt -from __future__ import unicode_literals import unittest diff --git a/erpnext/accounts/doctype/fiscal_year/__init__.py b/erpnext/accounts/doctype/fiscal_year/__init__.py index baffc488252..e69de29bb2d 100644 --- a/erpnext/accounts/doctype/fiscal_year/__init__.py +++ b/erpnext/accounts/doctype/fiscal_year/__init__.py @@ -1 +0,0 @@ -from __future__ import unicode_literals diff --git a/erpnext/accounts/doctype/fiscal_year/fiscal_year.py b/erpnext/accounts/doctype/fiscal_year/fiscal_year.py index 6854ac910d2..dd893f9fc80 100644 --- a/erpnext/accounts/doctype/fiscal_year/fiscal_year.py +++ b/erpnext/accounts/doctype/fiscal_year/fiscal_year.py @@ -1,7 +1,6 @@ # Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors # License: GNU General Public License v3. See license.txt -from __future__ import unicode_literals import frappe from dateutil.relativedelta import relativedelta diff --git a/erpnext/accounts/doctype/fiscal_year/fiscal_year_dashboard.py b/erpnext/accounts/doctype/fiscal_year/fiscal_year_dashboard.py index 58480df1190..892a2c62cff 100644 --- a/erpnext/accounts/doctype/fiscal_year/fiscal_year_dashboard.py +++ b/erpnext/accounts/doctype/fiscal_year/fiscal_year_dashboard.py @@ -1,5 +1,3 @@ -from __future__ import unicode_literals - from frappe import _ @@ -13,7 +11,7 @@ def get_data(): }, { 'label': _('References'), - 'items': ['Period Closing Voucher', 'Tax Withholding Category'] + 'items': ['Period Closing Voucher'] }, { 'label': _('Target Details'), diff --git a/erpnext/accounts/doctype/fiscal_year/test_fiscal_year.py b/erpnext/accounts/doctype/fiscal_year/test_fiscal_year.py index b0365afa827..bc8c6abeff3 100644 --- a/erpnext/accounts/doctype/fiscal_year/test_fiscal_year.py +++ b/erpnext/accounts/doctype/fiscal_year/test_fiscal_year.py @@ -1,7 +1,6 @@ # Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors # License: GNU General Public License v3. See license.txt -from __future__ import unicode_literals import unittest diff --git a/erpnext/accounts/doctype/fiscal_year_company/fiscal_year_company.json b/erpnext/accounts/doctype/fiscal_year_company/fiscal_year_company.json index 3eb0d74ed33..67acb26c7ee 100644 --- a/erpnext/accounts/doctype/fiscal_year_company/fiscal_year_company.json +++ b/erpnext/accounts/doctype/fiscal_year_company/fiscal_year_company.json @@ -1,63 +1,33 @@ { - "allow_copy": 0, - "allow_import": 0, - "allow_rename": 0, - "beta": 0, - "creation": "2014-10-02 13:35:44.155278", - "custom": 0, - "docstatus": 0, - "doctype": "DocType", - "document_type": "Setup", - "editable_grid": 1, + "actions": [], + "creation": "2014-10-02 13:35:44.155278", + "doctype": "DocType", + "document_type": "Setup", + "editable_grid": 1, + "engine": "InnoDB", + "field_order": [ + "company" + ], "fields": [ { - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "fieldname": "company", - "fieldtype": "Link", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_list_view": 1, - "label": "Company", - "length": 0, - "no_copy": 0, - "options": "Company", - "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 + "fieldname": "company", + "fieldtype": "Link", + "ignore_user_permissions": 1, + "in_list_view": 1, + "label": "Company", + "options": "Company" } - ], - "hide_heading": 0, - "hide_toolbar": 0, - "idx": 0, - "image_view": 0, - "in_create": 0, - - "is_submittable": 0, - "issingle": 0, - "istable": 1, - "max_attachments": 0, - "modified": "2016-07-11 03:28:00.505946", - "modified_by": "Administrator", - "module": "Accounts", - "name": "Fiscal Year Company", - "name_case": "", - "owner": "Administrator", - "permissions": [], - "quick_entry": 0, - "read_only": 0, - "read_only_onload": 0, - "sort_field": "modified", - "sort_order": "DESC", - "track_seen": 0 + ], + "index_web_pages_for_search": 1, + "istable": 1, + "links": [], + "modified": "2021-09-28 18:01:53.495929", + "modified_by": "Administrator", + "module": "Accounts", + "name": "Fiscal Year Company", + "owner": "Administrator", + "permissions": [], + "sort_field": "modified", + "sort_order": "DESC", + "track_changes": 1 } \ No newline at end of file diff --git a/erpnext/accounts/doctype/fiscal_year_company/fiscal_year_company.py b/erpnext/accounts/doctype/fiscal_year_company/fiscal_year_company.py index b9c57f67b0e..d5db78dfb91 100644 --- a/erpnext/accounts/doctype/fiscal_year_company/fiscal_year_company.py +++ b/erpnext/accounts/doctype/fiscal_year_company/fiscal_year_company.py @@ -1,7 +1,6 @@ # Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors and contributors # For license information, please see license.txt -from __future__ import unicode_literals from frappe.model.document import Document diff --git a/erpnext/accounts/doctype/gl_entry/__init__.py b/erpnext/accounts/doctype/gl_entry/__init__.py index baffc488252..e69de29bb2d 100644 --- a/erpnext/accounts/doctype/gl_entry/__init__.py +++ b/erpnext/accounts/doctype/gl_entry/__init__.py @@ -1 +0,0 @@ -from __future__ import unicode_literals diff --git a/erpnext/accounts/doctype/gl_entry/gl_entry.py b/erpnext/accounts/doctype/gl_entry/gl_entry.py index 1e983b1d429..9d1452b1b38 100644 --- a/erpnext/accounts/doctype/gl_entry/gl_entry.py +++ b/erpnext/accounts/doctype/gl_entry/gl_entry.py @@ -1,7 +1,6 @@ # Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors # License: GNU General Public License v3. See license.txt -from __future__ import unicode_literals import frappe from frappe import _ @@ -9,7 +8,6 @@ from frappe.model.document import Document from frappe.model.meta import get_field_precision from frappe.model.naming import set_name_from_naming_options from frappe.utils import flt, fmt_money -from six import iteritems import erpnext from erpnext.accounts.doctype.accounting_dimension.accounting_dimension import ( @@ -58,7 +56,8 @@ class GLEntry(Document): # Update outstanding amt on against voucher if (self.against_voucher_type in ['Journal Entry', 'Sales Invoice', 'Purchase Invoice', 'Fees'] - and self.against_voucher and self.flags.update_outstanding == 'Yes'): + and self.against_voucher and self.flags.update_outstanding == 'Yes' + and not frappe.flags.is_reverse_depr_entry): update_outstanding_amt(self.account, self.party_type, self.party, self.against_voucher_type, self.against_voucher) @@ -115,7 +114,7 @@ class GLEntry(Document): def validate_allowed_dimensions(self): dimension_filter_map = get_dimension_filter_map() - for key, value in iteritems(dimension_filter_map): + for key, value in dimension_filter_map.items(): dimension = key[0] account = key[1] diff --git a/erpnext/accounts/doctype/gl_entry/test_gl_entry.py b/erpnext/accounts/doctype/gl_entry/test_gl_entry.py index 14959520767..3de23946892 100644 --- a/erpnext/accounts/doctype/gl_entry/test_gl_entry.py +++ b/erpnext/accounts/doctype/gl_entry/test_gl_entry.py @@ -1,7 +1,6 @@ # Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors # License: GNU General Public License v3. See license.txt -from __future__ import unicode_literals import unittest diff --git a/erpnext/accounts/doctype/gst_account/gst_account.py b/erpnext/accounts/doctype/gst_account/gst_account.py index 9ca3f9ac51d..befca41b57e 100644 --- a/erpnext/accounts/doctype/gst_account/gst_account.py +++ b/erpnext/accounts/doctype/gst_account/gst_account.py @@ -1,8 +1,6 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2018, Frappe Technologies Pvt. Ltd. and contributors # For license information, please see license.txt -from __future__ import unicode_literals from frappe.model.document import Document diff --git a/erpnext/accounts/doctype/invoice_discounting/invoice_discounting.py b/erpnext/accounts/doctype/invoice_discounting/invoice_discounting.py index 8867f1cd9bf..09c389de738 100644 --- a/erpnext/accounts/doctype/invoice_discounting/invoice_discounting.py +++ b/erpnext/accounts/doctype/invoice_discounting/invoice_discounting.py @@ -1,8 +1,6 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2019, Frappe Technologies Pvt. Ltd. and contributors # For license information, please see license.txt -from __future__ import unicode_literals import json diff --git a/erpnext/accounts/doctype/invoice_discounting/invoice_discounting_dashboard.py b/erpnext/accounts/doctype/invoice_discounting/invoice_discounting_dashboard.py index bab8e46c31e..b7484293023 100644 --- a/erpnext/accounts/doctype/invoice_discounting/invoice_discounting_dashboard.py +++ b/erpnext/accounts/doctype/invoice_discounting/invoice_discounting_dashboard.py @@ -1,5 +1,3 @@ -from __future__ import unicode_literals - from frappe import _ diff --git a/erpnext/accounts/doctype/invoice_discounting/test_invoice_discounting.py b/erpnext/accounts/doctype/invoice_discounting/test_invoice_discounting.py index 58aea92e817..d1d4be36f17 100644 --- a/erpnext/accounts/doctype/invoice_discounting/test_invoice_discounting.py +++ b/erpnext/accounts/doctype/invoice_discounting/test_invoice_discounting.py @@ -1,7 +1,5 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2019, Frappe Technologies Pvt. Ltd. and Contributors # See license.txt -from __future__ import unicode_literals import unittest diff --git a/erpnext/accounts/doctype/item_tax_template/item_tax_template.py b/erpnext/accounts/doctype/item_tax_template/item_tax_template.py index 1e26afe0253..0ceb6a0bc23 100644 --- a/erpnext/accounts/doctype/item_tax_template/item_tax_template.py +++ b/erpnext/accounts/doctype/item_tax_template/item_tax_template.py @@ -1,8 +1,6 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2018, Frappe Technologies Pvt. Ltd. and contributors # For license information, please see license.txt -from __future__ import unicode_literals import frappe from frappe import _ diff --git a/erpnext/accounts/doctype/item_tax_template/item_tax_template_dashboard.py b/erpnext/accounts/doctype/item_tax_template/item_tax_template_dashboard.py index 3d80a9785f0..af01c57560f 100644 --- a/erpnext/accounts/doctype/item_tax_template/item_tax_template_dashboard.py +++ b/erpnext/accounts/doctype/item_tax_template/item_tax_template_dashboard.py @@ -1,5 +1,3 @@ -from __future__ import unicode_literals - from frappe import _ diff --git a/erpnext/accounts/doctype/item_tax_template/test_item_tax_template.py b/erpnext/accounts/doctype/item_tax_template/test_item_tax_template.py index 46bb300e37d..e8638bb355d 100644 --- a/erpnext/accounts/doctype/item_tax_template/test_item_tax_template.py +++ b/erpnext/accounts/doctype/item_tax_template/test_item_tax_template.py @@ -1,7 +1,5 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2018, Frappe Technologies Pvt. Ltd. and Contributors # See license.txt -from __future__ import unicode_literals import unittest diff --git a/erpnext/accounts/doctype/item_tax_template_detail/item_tax_template_detail.py b/erpnext/accounts/doctype/item_tax_template_detail/item_tax_template_detail.py index aa3b5420d60..221081e84d7 100644 --- a/erpnext/accounts/doctype/item_tax_template_detail/item_tax_template_detail.py +++ b/erpnext/accounts/doctype/item_tax_template_detail/item_tax_template_detail.py @@ -1,8 +1,6 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2018, Frappe Technologies Pvt. Ltd. and contributors # For license information, please see license.txt -from __future__ import unicode_literals from frappe.model.document import Document diff --git a/erpnext/accounts/doctype/journal_entry/journal_entry.json b/erpnext/accounts/doctype/journal_entry/journal_entry.json index b7bbb74ce94..20678d787b4 100644 --- a/erpnext/accounts/doctype/journal_entry/journal_entry.json +++ b/erpnext/accounts/doctype/journal_entry/journal_entry.json @@ -13,10 +13,12 @@ "voucher_type", "naming_series", "finance_book", + "tax_withholding_category", "column_break1", "from_template", "company", "posting_date", + "apply_tds", "2_add_edit_gl_entries", "accounts", "section_break99", @@ -498,16 +500,32 @@ "options": "Journal Entry Template", "print_hide": 1, "report_hide": 1 + }, + { + "depends_on": "eval:doc.apply_tds", + "fieldname": "tax_withholding_category", + "fieldtype": "Link", + "label": "Tax Withholding Category", + "mandatory_depends_on": "eval:doc.apply_tds", + "options": "Tax Withholding Category" + }, + { + "default": "0", + "depends_on": "eval:['Credit Note', 'Debit Note'].includes(doc.voucher_type)", + "fieldname": "apply_tds", + "fieldtype": "Check", + "label": "Apply Tax Withholding Amount " } ], "icon": "fa fa-file-text", "idx": 176, "is_submittable": 1, "links": [], - "modified": "2020-10-30 13:56:01.121995", + "modified": "2021-09-09 15:31:14.484029", "modified_by": "Administrator", "module": "Accounts", "name": "Journal Entry", + "naming_rule": "By \"Naming Series\" field", "owner": "Administrator", "permissions": [ { diff --git a/erpnext/accounts/doctype/journal_entry/journal_entry.py b/erpnext/accounts/doctype/journal_entry/journal_entry.py index 24368f04419..ca172650782 100644 --- a/erpnext/accounts/doctype/journal_entry/journal_entry.py +++ b/erpnext/accounts/doctype/journal_entry/journal_entry.py @@ -1,20 +1,21 @@ # Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors # License: GNU General Public License v3. See license.txt -from __future__ import unicode_literals import json import frappe from frappe import _, msgprint, scrub from frappe.utils import cint, cstr, flt, fmt_money, formatdate, get_link_to_form, nowdate -from six import iteritems, string_types import erpnext from erpnext.accounts.deferred_revenue import get_deferred_booking_accounts from erpnext.accounts.doctype.invoice_discounting.invoice_discounting import ( get_party_account_based_on_invoice_discounting, ) +from erpnext.accounts.doctype.tax_withholding_category.tax_withholding_category import ( + get_party_tax_withholding_details, +) from erpnext.accounts.party import get_party_account from erpnext.accounts.utils import ( check_if_stock_and_account_balance_synced, @@ -55,9 +56,13 @@ class JournalEntry(AccountsController): if not frappe.flags.in_import: self.validate_total_debit_and_credit() - self.validate_against_jv() + if not frappe.flags.is_reverse_depr_entry: + self.validate_against_jv() + self.validate_stock_accounts() + self.validate_reference_doc() - self.set_against_account() + if self.docstatus == 0: + self.set_against_account() self.create_remarks() self.set_print_format_fields() self.validate_expense_claim() @@ -65,7 +70,10 @@ class JournalEntry(AccountsController): self.validate_empty_accounts_table() self.set_account_and_party_balance() self.validate_inter_company_accounts() - self.validate_stock_accounts() + + if self.docstatus == 0: + self.apply_tax_withholding() + if not self.title: self.title = self.get_title() @@ -107,7 +115,7 @@ class JournalEntry(AccountsController): if d.reference_type in ("Sales Order", "Purchase Order", "Employee Advance"): advance_paid.setdefault(d.reference_type, []).append(d.reference_name) - for voucher_type, order_list in iteritems(advance_paid): + 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() @@ -139,6 +147,72 @@ class JournalEntry(AccountsController): frappe.throw(_("Account: {0} can only be updated via Stock Transactions") .format(account), StockAccountInvalidTransaction) + def apply_tax_withholding(self): + from erpnext.accounts.report.general_ledger.general_ledger import get_account_type_map + + if not self.apply_tds or self.voucher_type not in ('Debit Note', 'Credit Note'): + return + + parties = [d.party for d in self.get('accounts') if d.party] + parties = list(set(parties)) + + if len(parties) > 1: + frappe.throw(_("Cannot apply TDS against multiple parties in one entry")) + + account_type_map = get_account_type_map(self.company) + party_type = 'supplier' if self.voucher_type == 'Credit Note' else 'customer' + doctype = 'Purchase Invoice' if self.voucher_type == 'Credit Note' else 'Sales Invoice' + debit_or_credit = 'debit_in_account_currency' if self.voucher_type == 'Credit Note' else 'credit_in_account_currency' + rev_debit_or_credit = 'credit_in_account_currency' if debit_or_credit == 'debit_in_account_currency' else 'debit_in_account_currency' + + party_account = get_party_account(party_type.title(), parties[0], self.company) + + net_total = sum(d.get(debit_or_credit) for d in self.get('accounts') if account_type_map.get(d.account) + not in ('Tax', 'Chargeable')) + + party_amount = sum(d.get(rev_debit_or_credit) for d in self.get('accounts') if d.account == party_account) + + inv = frappe._dict({ + party_type: parties[0], + 'doctype': doctype, + 'company': self.company, + 'posting_date': self.posting_date, + 'net_total': net_total + }) + + tax_withholding_details = get_party_tax_withholding_details(inv, self.tax_withholding_category) + + if not tax_withholding_details: + return + + accounts = [] + for d in self.get('accounts'): + if d.get('account') == tax_withholding_details.get("account_head"): + d.update({ + 'account': tax_withholding_details.get("account_head"), + debit_or_credit: tax_withholding_details.get('tax_amount') + }) + + accounts.append(d.get('account')) + + if d.get('account') == party_account: + d.update({ + rev_debit_or_credit: party_amount - tax_withholding_details.get('tax_amount') + }) + + if not accounts or tax_withholding_details.get("account_head") not in accounts: + self.append("accounts", { + 'account': tax_withholding_details.get("account_head"), + rev_debit_or_credit: tax_withholding_details.get('tax_amount'), + 'against_account': parties[0] + }) + + to_remove = [d for d in self.get('accounts') + if not d.get(rev_debit_or_credit) and d.account == tax_withholding_details.get("account_head")] + + for d in to_remove: + self.remove(d) + def update_inter_company_jv(self): if self.voucher_type == "Inter Company Journal Entry" and self.inter_company_journal_entry_reference: frappe.db.set_value("Journal Entry", self.inter_company_journal_entry_reference,\ @@ -356,7 +430,7 @@ class JournalEntry(AccountsController): def validate_orders(self): """Validate totals, closed and docstatus for orders""" - for reference_name, total in iteritems(self.reference_totals): + for reference_name, total in self.reference_totals.items(): reference_type = self.reference_types[reference_name] account = self.reference_accounts[reference_name] @@ -387,7 +461,7 @@ class JournalEntry(AccountsController): def validate_invoices(self): """Validate totals and docstatus for invoices""" - for reference_name, total in iteritems(self.reference_totals): + for reference_name, total in self.reference_totals.items(): reference_type = self.reference_types[reference_name] if (reference_type in ("Sales Invoice", "Purchase Invoice") and @@ -932,7 +1006,7 @@ def get_outstanding(args): if not frappe.has_permission("Account"): frappe.msgprint(_("No Permission"), raise_exception=1) - if isinstance(args, string_types): + if isinstance(args, str): args = json.loads(args) company_currency = erpnext.get_company_currency(args.get("company")) diff --git a/erpnext/accounts/doctype/journal_entry/test_journal_entry.py b/erpnext/accounts/doctype/journal_entry/test_journal_entry.py index d03a08851a6..481462b2aba 100644 --- a/erpnext/accounts/doctype/journal_entry/test_journal_entry.py +++ b/erpnext/accounts/doctype/journal_entry/test_journal_entry.py @@ -1,7 +1,6 @@ # Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors # License: GNU General Public License v3. See license.txt -from __future__ import unicode_literals import unittest diff --git a/erpnext/accounts/doctype/journal_entry_account/journal_entry_account.py b/erpnext/accounts/doctype/journal_entry_account/journal_entry_account.py index 86d3df4dc22..534b589273c 100644 --- a/erpnext/accounts/doctype/journal_entry_account/journal_entry_account.py +++ b/erpnext/accounts/doctype/journal_entry_account/journal_entry_account.py @@ -1,7 +1,6 @@ # Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors and contributors # For license information, please see license.txt -from __future__ import unicode_literals from frappe.model.document import Document diff --git a/erpnext/accounts/doctype/journal_entry_template/journal_entry_template.py b/erpnext/accounts/doctype/journal_entry_template/journal_entry_template.py index f0813f5e275..2da72c20ad8 100644 --- a/erpnext/accounts/doctype/journal_entry_template/journal_entry_template.py +++ b/erpnext/accounts/doctype/journal_entry_template/journal_entry_template.py @@ -1,8 +1,6 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2020, Frappe Technologies Pvt. Ltd. and contributors # For license information, please see license.txt -from __future__ import unicode_literals import frappe from frappe.model.document import Document diff --git a/erpnext/accounts/doctype/journal_entry_template/test_journal_entry_template.py b/erpnext/accounts/doctype/journal_entry_template/test_journal_entry_template.py index 61fea94e823..868a0ee7beb 100644 --- a/erpnext/accounts/doctype/journal_entry_template/test_journal_entry_template.py +++ b/erpnext/accounts/doctype/journal_entry_template/test_journal_entry_template.py @@ -1,7 +1,5 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2020, Frappe Technologies Pvt. Ltd. and Contributors # See license.txt -from __future__ import unicode_literals # import frappe import unittest diff --git a/erpnext/accounts/doctype/journal_entry_template_account/journal_entry_template_account.py b/erpnext/accounts/doctype/journal_entry_template_account/journal_entry_template_account.py index d0408ca2fcd..f84fddd54ca 100644 --- a/erpnext/accounts/doctype/journal_entry_template_account/journal_entry_template_account.py +++ b/erpnext/accounts/doctype/journal_entry_template_account/journal_entry_template_account.py @@ -1,8 +1,6 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2020, Frappe Technologies Pvt. Ltd. and contributors # For license information, please see license.txt -from __future__ import unicode_literals # import frappe from frappe.model.document import Document diff --git a/erpnext/accounts/doctype/loyalty_point_entry/loyalty_point_entry.py b/erpnext/accounts/doctype/loyalty_point_entry/loyalty_point_entry.py index 0813926f5f2..f460b9f7953 100644 --- a/erpnext/accounts/doctype/loyalty_point_entry/loyalty_point_entry.py +++ b/erpnext/accounts/doctype/loyalty_point_entry/loyalty_point_entry.py @@ -1,8 +1,6 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2018, Frappe Technologies Pvt. Ltd. and contributors # For license information, please see license.txt -from __future__ import unicode_literals import frappe from frappe.model.document import Document @@ -16,7 +14,7 @@ class LoyaltyPointEntry(Document): def get_loyalty_point_entries(customer, loyalty_program, company, expiry_date=None): if not expiry_date: - date = today() + expiry_date = today() return frappe.db.sql(''' select name, loyalty_points, expiry_date, loyalty_program_tier, invoice_type, invoice diff --git a/erpnext/accounts/doctype/loyalty_point_entry/test_loyalty_point_entry.py b/erpnext/accounts/doctype/loyalty_point_entry/test_loyalty_point_entry.py index 07856cfd5d6..cd38559d1d1 100644 --- a/erpnext/accounts/doctype/loyalty_point_entry/test_loyalty_point_entry.py +++ b/erpnext/accounts/doctype/loyalty_point_entry/test_loyalty_point_entry.py @@ -1,7 +1,5 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2018, Frappe Technologies Pvt. Ltd. and Contributors # See license.txt -from __future__ import unicode_literals import unittest diff --git a/erpnext/accounts/doctype/loyalty_point_entry_redemption/loyalty_point_entry_redemption.py b/erpnext/accounts/doctype/loyalty_point_entry_redemption/loyalty_point_entry_redemption.py index 506e2ce8398..bc8f5c70a7c 100644 --- a/erpnext/accounts/doctype/loyalty_point_entry_redemption/loyalty_point_entry_redemption.py +++ b/erpnext/accounts/doctype/loyalty_point_entry_redemption/loyalty_point_entry_redemption.py @@ -1,8 +1,6 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2018, Frappe Technologies Pvt. Ltd. and contributors # For license information, please see license.txt -from __future__ import unicode_literals from frappe.model.document import Document diff --git a/erpnext/accounts/doctype/loyalty_program/loyalty_program.js b/erpnext/accounts/doctype/loyalty_program/loyalty_program.js index f90f86728de..6951b2a2b32 100644 --- a/erpnext/accounts/doctype/loyalty_program/loyalty_program.js +++ b/erpnext/accounts/doctype/loyalty_program/loyalty_program.js @@ -6,7 +6,7 @@ frappe.provide("erpnext.accounts.dimensions"); frappe.ui.form.on('Loyalty Program', { setup: function(frm) { var help_content = - ` + `
- - """.format(doctype, docnames) - - message += """ -

diff --git a/erpnext/accounts/doctype/loyalty_program/loyalty_program.py b/erpnext/accounts/doctype/loyalty_program/loyalty_program.py index 89ed461fd5d..70da03b27f3 100644 --- a/erpnext/accounts/doctype/loyalty_program/loyalty_program.py +++ b/erpnext/accounts/doctype/loyalty_program/loyalty_program.py @@ -1,8 +1,6 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2018, Frappe Technologies Pvt. Ltd. and contributors # For license information, please see license.txt -from __future__ import unicode_literals import frappe from frappe import _ diff --git a/erpnext/accounts/doctype/loyalty_program/loyalty_program_dashboard.py b/erpnext/accounts/doctype/loyalty_program/loyalty_program_dashboard.py index 267bbbf00b2..25328e501ee 100644 --- a/erpnext/accounts/doctype/loyalty_program/loyalty_program_dashboard.py +++ b/erpnext/accounts/doctype/loyalty_program/loyalty_program_dashboard.py @@ -1,6 +1,3 @@ -from __future__ import unicode_literals - - def get_data(): return { 'fieldname': 'loyalty_program', diff --git a/erpnext/accounts/doctype/loyalty_program/test_loyalty_program.py b/erpnext/accounts/doctype/loyalty_program/test_loyalty_program.py index a039e32b8b9..82c14324f5c 100644 --- a/erpnext/accounts/doctype/loyalty_program/test_loyalty_program.py +++ b/erpnext/accounts/doctype/loyalty_program/test_loyalty_program.py @@ -1,7 +1,5 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2018, Frappe Technologies Pvt. Ltd. and Contributors # See license.txt -from __future__ import unicode_literals import unittest diff --git a/erpnext/accounts/doctype/loyalty_program_collection/loyalty_program_collection.py b/erpnext/accounts/doctype/loyalty_program_collection/loyalty_program_collection.py index 4bbcf3ae9f0..c462d5f0657 100644 --- a/erpnext/accounts/doctype/loyalty_program_collection/loyalty_program_collection.py +++ b/erpnext/accounts/doctype/loyalty_program_collection/loyalty_program_collection.py @@ -1,8 +1,6 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2018, Frappe Technologies Pvt. Ltd. and contributors # For license information, please see license.txt -from __future__ import unicode_literals from frappe.model.document import Document diff --git a/erpnext/accounts/doctype/mode_of_payment/__init__.py b/erpnext/accounts/doctype/mode_of_payment/__init__.py index baffc488252..e69de29bb2d 100644 --- a/erpnext/accounts/doctype/mode_of_payment/__init__.py +++ b/erpnext/accounts/doctype/mode_of_payment/__init__.py @@ -1 +0,0 @@ -from __future__ import unicode_literals diff --git a/erpnext/accounts/doctype/mode_of_payment/mode_of_payment.py b/erpnext/accounts/doctype/mode_of_payment/mode_of_payment.py index dfe42df226a..f21d1b9baa9 100644 --- a/erpnext/accounts/doctype/mode_of_payment/mode_of_payment.py +++ b/erpnext/accounts/doctype/mode_of_payment/mode_of_payment.py @@ -1,7 +1,6 @@ # Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors # License: GNU General Public License v3. See license.txt -from __future__ import unicode_literals import frappe from frappe import _ diff --git a/erpnext/accounts/doctype/mode_of_payment/test_mode_of_payment.py b/erpnext/accounts/doctype/mode_of_payment/test_mode_of_payment.py index 299687b067e..2ff02a7c4dc 100644 --- a/erpnext/accounts/doctype/mode_of_payment/test_mode_of_payment.py +++ b/erpnext/accounts/doctype/mode_of_payment/test_mode_of_payment.py @@ -1,7 +1,5 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors # See license.txt -from __future__ import unicode_literals import unittest diff --git a/erpnext/accounts/doctype/mode_of_payment_account/mode_of_payment_account.py b/erpnext/accounts/doctype/mode_of_payment_account/mode_of_payment_account.py index 40b5f302f2c..3d3bba6b23d 100644 --- a/erpnext/accounts/doctype/mode_of_payment_account/mode_of_payment_account.py +++ b/erpnext/accounts/doctype/mode_of_payment_account/mode_of_payment_account.py @@ -1,7 +1,6 @@ # Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors and contributors # For license information, please see license.txt -from __future__ import unicode_literals from frappe.model.document import Document diff --git a/erpnext/accounts/doctype/monthly_distribution/monthly_distribution.py b/erpnext/accounts/doctype/monthly_distribution/monthly_distribution.py index c0e00d62099..a8c5f68c110 100644 --- a/erpnext/accounts/doctype/monthly_distribution/monthly_distribution.py +++ b/erpnext/accounts/doctype/monthly_distribution/monthly_distribution.py @@ -1,7 +1,6 @@ # Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors # License: GNU General Public License v3. See license.txt -from __future__ import unicode_literals import frappe from frappe import _ diff --git a/erpnext/accounts/doctype/monthly_distribution/monthly_distribution_dashboard.py b/erpnext/accounts/doctype/monthly_distribution/monthly_distribution_dashboard.py index 912bd9e331a..96008c47339 100644 --- a/erpnext/accounts/doctype/monthly_distribution/monthly_distribution_dashboard.py +++ b/erpnext/accounts/doctype/monthly_distribution/monthly_distribution_dashboard.py @@ -1,5 +1,3 @@ -from __future__ import unicode_literals - from frappe import _ diff --git a/erpnext/accounts/doctype/monthly_distribution/test_monthly_distribution.py b/erpnext/accounts/doctype/monthly_distribution/test_monthly_distribution.py index 63faa158f15..4a878b2aaf7 100644 --- a/erpnext/accounts/doctype/monthly_distribution/test_monthly_distribution.py +++ b/erpnext/accounts/doctype/monthly_distribution/test_monthly_distribution.py @@ -1,7 +1,6 @@ # Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors and Contributors # See license.txt -from __future__ import unicode_literals import unittest diff --git a/erpnext/accounts/doctype/monthly_distribution_percentage/monthly_distribution_percentage.py b/erpnext/accounts/doctype/monthly_distribution_percentage/monthly_distribution_percentage.py index 8ec30c79af7..274e2b643f9 100644 --- a/erpnext/accounts/doctype/monthly_distribution_percentage/monthly_distribution_percentage.py +++ b/erpnext/accounts/doctype/monthly_distribution_percentage/monthly_distribution_percentage.py @@ -1,7 +1,6 @@ # Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors and contributors # For license information, please see license.txt -from __future__ import unicode_literals from frappe.model.document import Document diff --git a/erpnext/accounts/doctype/opening_invoice_creation_tool/opening_invoice_creation_tool.py b/erpnext/accounts/doctype/opening_invoice_creation_tool/opening_invoice_creation_tool.py index 2b94bf4c1f1..2a923f009db 100644 --- a/erpnext/accounts/doctype/opening_invoice_creation_tool/opening_invoice_creation_tool.py +++ b/erpnext/accounts/doctype/opening_invoice_creation_tool/opening_invoice_creation_tool.py @@ -1,8 +1,6 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2017, Frappe Technologies Pvt. Ltd. and contributors # For license information, please see license.txt -from __future__ import unicode_literals import traceback from json import dumps diff --git a/erpnext/accounts/doctype/opening_invoice_creation_tool/test_opening_invoice_creation_tool.py b/erpnext/accounts/doctype/opening_invoice_creation_tool/test_opening_invoice_creation_tool.py index ed3c6a9da0a..c795e83c56b 100644 --- a/erpnext/accounts/doctype/opening_invoice_creation_tool/test_opening_invoice_creation_tool.py +++ b/erpnext/accounts/doctype/opening_invoice_creation_tool/test_opening_invoice_creation_tool.py @@ -1,7 +1,5 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2017, Frappe Technologies Pvt. Ltd. and Contributors # See license.txt -from __future__ import unicode_literals import unittest diff --git a/erpnext/accounts/doctype/opening_invoice_creation_tool_item/opening_invoice_creation_tool_item.py b/erpnext/accounts/doctype/opening_invoice_creation_tool_item/opening_invoice_creation_tool_item.py index 4008022a26b..6c0ca4a19f3 100644 --- a/erpnext/accounts/doctype/opening_invoice_creation_tool_item/opening_invoice_creation_tool_item.py +++ b/erpnext/accounts/doctype/opening_invoice_creation_tool_item/opening_invoice_creation_tool_item.py @@ -1,8 +1,6 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2017, Frappe Technologies Pvt. Ltd. and contributors # For license information, please see license.txt -from __future__ import unicode_literals from frappe.model.document import Document diff --git a/erpnext/accounts/doctype/party_account/party_account.py b/erpnext/accounts/doctype/party_account/party_account.py index 08d67c7a7be..cd270b1184c 100644 --- a/erpnext/accounts/doctype/party_account/party_account.py +++ b/erpnext/accounts/doctype/party_account/party_account.py @@ -1,7 +1,6 @@ # Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors and contributors # For license information, please see license.txt -from __future__ import unicode_literals from frappe.model.document import Document diff --git a/erpnext/accounts/doctype/party_link/party_link.py b/erpnext/accounts/doctype/party_link/party_link.py index daf667caf0c..e9f813c17c6 100644 --- a/erpnext/accounts/doctype/party_link/party_link.py +++ b/erpnext/accounts/doctype/party_link/party_link.py @@ -25,3 +25,17 @@ class PartyLink(Document): if existing_party_link: frappe.throw(_('{} {} is already linked with another {}') .format(self.primary_role, self.primary_party, existing_party_link[0])) + + +@frappe.whitelist() +def create_party_link(primary_role, primary_party, secondary_party): + party_link = frappe.new_doc('Party Link') + party_link.primary_role = primary_role + party_link.primary_party = primary_party + party_link.secondary_role = 'Customer' if primary_role == 'Supplier' else 'Supplier' + party_link.secondary_party = secondary_party + + party_link.save(ignore_permissions=True) + + return party_link + diff --git a/erpnext/accounts/doctype/payment_entry/payment_entry.json b/erpnext/accounts/doctype/payment_entry/payment_entry.json index 6f362c1fbb9..ee2e319a6fc 100644 --- a/erpnext/accounts/doctype/payment_entry/payment_entry.json +++ b/erpnext/accounts/doctype/payment_entry/payment_entry.json @@ -27,10 +27,12 @@ "payment_accounts_section", "party_balance", "paid_from", + "paid_from_account_type", "paid_from_account_currency", "paid_from_account_balance", "column_break_18", "paid_to", + "paid_to_account_type", "paid_to_account_currency", "paid_to_account_balance", "payment_amounts_section", @@ -440,7 +442,8 @@ "depends_on": "eval:(doc.paid_from && doc.paid_to)", "fieldname": "reference_no", "fieldtype": "Data", - "label": "Cheque/Reference No" + "label": "Cheque/Reference No", + "mandatory_depends_on": "eval:(doc.paid_from_account_type == 'Bank' || doc.paid_to_account_type == 'Bank')" }, { "fieldname": "column_break_23", @@ -452,6 +455,7 @@ "fieldname": "reference_date", "fieldtype": "Date", "label": "Cheque/Reference Date", + "mandatory_depends_on": "eval:(doc.paid_from_account_type == 'Bank' || doc.paid_to_account_type == 'Bank')", "search_index": 1 }, { @@ -707,15 +711,30 @@ "label": "Received Amount After Tax (Company Currency)", "options": "Company:company:default_currency", "read_only": 1 + }, + { + "fetch_from": "paid_from.account_type", + "fieldname": "paid_from_account_type", + "fieldtype": "Data", + "hidden": 1, + "label": "Paid From Account Type" + }, + { + "fetch_from": "paid_to.account_type", + "fieldname": "paid_to_account_type", + "fieldtype": "Data", + "hidden": 1, + "label": "Paid To Account Type" } ], "index_web_pages_for_search": 1, "is_submittable": 1, "links": [], - "modified": "2021-07-09 08:58:15.008761", + "modified": "2021-10-22 17:50:24.632806", "modified_by": "Administrator", "module": "Accounts", "name": "Payment Entry", + "naming_rule": "By \"Naming Series\" field", "owner": "Administrator", "permissions": [ { diff --git a/erpnext/accounts/doctype/payment_entry/payment_entry.py b/erpnext/accounts/doctype/payment_entry/payment_entry.py index a5303215d5b..26fd16a4fd5 100644 --- a/erpnext/accounts/doctype/payment_entry/payment_entry.py +++ b/erpnext/accounts/doctype/payment_entry/payment_entry.py @@ -1,15 +1,12 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and contributors # For license information, please see license.txt -from __future__ import unicode_literals import json import frappe from frappe import ValidationError, _, scrub, throw from frappe.utils import cint, comma_or, flt, getdate, nowdate -from six import iteritems, string_types import erpnext from erpnext.accounts.doctype.bank_account.bank_account import ( @@ -205,7 +202,7 @@ class PaymentEntry(AccountsController): ref_details = get_reference_details(d.reference_doctype, d.reference_name, self.party_account_currency) - for field, value in iteritems(ref_details): + for field, value in ref_details.items(): if d.exchange_gain_loss: # for cases where gain/loss is booked into invoice # exchange_gain_loss is calculated from invoice & populated @@ -389,7 +386,10 @@ class PaymentEntry(AccountsController): invoice_paid_amount_map[invoice_key]['outstanding'] = term.outstanding invoice_paid_amount_map[invoice_key]['discounted_amt'] = ref.total_amount * (term.discount / 100) - for key, allocated_amount in iteritems(invoice_payment_amount_map): + for idx, (key, allocated_amount) in enumerate(invoice_payment_amount_map.items(), 1): + if not invoice_paid_amount_map.get(key): + frappe.throw(_('Payment term {0} not used in {1}').format(key[0], key[1])) + outstanding = flt(invoice_paid_amount_map.get(key, {}).get('outstanding')) discounted_amt = flt(invoice_paid_amount_map.get(key, {}).get('discounted_amt')) @@ -404,7 +404,7 @@ class PaymentEntry(AccountsController): (allocated_amount - discounted_amt, discounted_amt, allocated_amount, key[1], key[0])) else: if allocated_amount > outstanding: - frappe.throw(_('Cannot allocate more than {0} against payment term {1}').format(outstanding, key[0])) + frappe.throw(_('Row #{0}: Cannot allocate more than {1} against payment term {2}').format(idx, outstanding, key[0])) if allocated_amount and outstanding: frappe.db.sql(""" @@ -502,12 +502,13 @@ class PaymentEntry(AccountsController): def validate_received_amount(self): if self.paid_from_account_currency == self.paid_to_account_currency: - if self.paid_amount != self.received_amount: + if self.paid_amount < self.received_amount: frappe.throw(_("Received Amount cannot be greater than Paid Amount")) def set_received_amount(self): self.base_received_amount = self.base_paid_amount - if self.paid_from_account_currency == self.paid_to_account_currency: + if self.paid_from_account_currency == self.paid_to_account_currency \ + and not self.payment_type == 'Internal Transfer': self.received_amount = self.paid_amount def set_amounts_after_tax(self): @@ -709,10 +710,14 @@ class PaymentEntry(AccountsController): dr_or_cr = "credit" if erpnext.get_party_account_type(self.party_type) == 'Receivable' else "debit" for d in self.get("references"): + cost_center = self.cost_center + if d.reference_doctype == "Sales Invoice" and not cost_center: + cost_center = frappe.db.get_value(d.reference_doctype, d.reference_name, "cost_center") gle = party_gl_dict.copy() gle.update({ "against_voucher_type": d.reference_doctype, - "against_voucher": d.reference_name + "against_voucher": d.reference_name, + "cost_center": cost_center }) allocated_amount_in_company_currency = flt(flt(d.allocated_amount) * flt(d.exchange_rate), @@ -906,7 +911,7 @@ class PaymentEntry(AccountsController): self.paid_amount_after_tax = self.paid_amount def determine_exclusive_rate(self): - if not any((cint(tax.included_in_paid_amount) for tax in self.get("taxes"))): + if not any(cint(tax.included_in_paid_amount) for tax in self.get("taxes")): return cumulated_tax_fraction = 0 @@ -1026,7 +1031,7 @@ def validate_inclusive_tax(tax, doc): @frappe.whitelist() def get_outstanding_reference_documents(args): - if isinstance(args, string_types): + if isinstance(args, str): args = json.loads(args) if args.get('party_type') == 'Member': @@ -1045,12 +1050,6 @@ def get_outstanding_reference_documents(args): party_account_currency = get_account_currency(args.get("party_account")) company_currency = frappe.get_cached_value('Company', args.get("company"), "default_currency") - # Get negative outstanding sales /purchase invoices - negative_outstanding_invoices = [] - if args.get("party_type") not in ["Student", "Employee"] and not args.get("voucher_no"): - negative_outstanding_invoices = get_negative_outstanding_invoices(args.get("party_type"), args.get("party"), - args.get("party_account"), args.get("company"), party_account_currency, company_currency) - # Get positive outstanding sales /purchase invoices/ Fees condition = "" if args.get("voucher_type") and args.get("voucher_no"): @@ -1097,6 +1096,12 @@ def get_outstanding_reference_documents(args): orders_to_be_billed = get_orders_to_be_billed(args.get("posting_date"),args.get("party_type"), args.get("party"), args.get("company"), party_account_currency, company_currency, filters=args) + # Get negative outstanding sales /purchase invoices + negative_outstanding_invoices = [] + if args.get("party_type") not in ["Student", "Employee"] and not args.get("voucher_no"): + negative_outstanding_invoices = get_negative_outstanding_invoices(args.get("party_type"), args.get("party"), + args.get("party_account"), party_account_currency, company_currency, condition=condition) + data = negative_outstanding_invoices + outstanding_invoices + orders_to_be_billed if not data: @@ -1129,22 +1134,26 @@ def split_invoices_based_on_payment_terms(outstanding_invoices): 'invoice_amount': flt(d.invoice_amount), 'outstanding_amount': flt(d.outstanding_amount), 'payment_amount': payment_term.payment_amount, - 'payment_term': payment_term.payment_term, - 'allocated_amount': payment_term.outstanding + 'payment_term': payment_term.payment_term })) + outstanding_invoices_after_split = [] if invoice_ref_based_on_payment_terms: for idx, ref in invoice_ref_based_on_payment_terms.items(): - voucher_no = outstanding_invoices[idx]['voucher_no'] - voucher_type = outstanding_invoices[idx]['voucher_type'] + voucher_no = ref[0]['voucher_no'] + voucher_type = ref[0]['voucher_type'] - frappe.msgprint(_("Spliting {} {} into {} rows as per payment terms").format( + frappe.msgprint(_("Spliting {} {} into {} row(s) as per Payment Terms").format( voucher_type, voucher_no, len(ref)), alert=True) - outstanding_invoices.pop(idx - 1) - outstanding_invoices += invoice_ref_based_on_payment_terms[idx] + outstanding_invoices_after_split += invoice_ref_based_on_payment_terms[idx] - return outstanding_invoices + existing_row = list(filter(lambda x: x.get('voucher_no') == voucher_no, outstanding_invoices)) + index = outstanding_invoices.index(existing_row[0]) + outstanding_invoices.pop(index) + + outstanding_invoices_after_split += outstanding_invoices + return outstanding_invoices_after_split def get_orders_to_be_billed(posting_date, party_type, party, company, party_account_currency, company_currency, cost_center=None, filters=None): @@ -1211,7 +1220,7 @@ def get_orders_to_be_billed(posting_date, party_type, party, return order_list def get_negative_outstanding_invoices(party_type, party, party_account, - company, party_account_currency, company_currency, cost_center=None): + party_account_currency, company_currency, cost_center=None, condition=None): voucher_type = "Sales Invoice" if party_type == "Customer" else "Purchase Invoice" supplier_condition = "" if voucher_type == "Purchase Invoice": @@ -1233,19 +1242,21 @@ def get_negative_outstanding_invoices(party_type, party, party_account, `tab{voucher_type}` where {party_type} = %s and {party_account} = %s and docstatus = 1 and - company = %s and outstanding_amount < 0 + outstanding_amount < 0 {supplier_condition} + {condition} order by posting_date, name """.format(**{ "supplier_condition": supplier_condition, + "condition": condition, "rounded_total_field": rounded_total_field, "grand_total_field": grand_total_field, "voucher_type": voucher_type, "party_type": scrub(party_type), "party_account": "debit_to" if party_type == "Customer" else "credit_to", "cost_center": cost_center - }), (party, party_account, company), as_dict=True) + }), (party, party_account), as_dict=True) @frappe.whitelist() diff --git a/erpnext/accounts/doctype/payment_entry/test_payment_entry.py b/erpnext/accounts/doctype/payment_entry/test_payment_entry.py index c90a3c503c2..cc3528e9aaa 100644 --- a/erpnext/accounts/doctype/payment_entry/test_payment_entry.py +++ b/erpnext/accounts/doctype/payment_entry/test_payment_entry.py @@ -1,7 +1,5 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors # See license.txt -from __future__ import unicode_literals import unittest diff --git a/erpnext/accounts/doctype/payment_entry_deduction/payment_entry_deduction.py b/erpnext/accounts/doctype/payment_entry_deduction/payment_entry_deduction.py index 9cfed7b56d3..b71dbb97d75 100644 --- a/erpnext/accounts/doctype/payment_entry_deduction/payment_entry_deduction.py +++ b/erpnext/accounts/doctype/payment_entry_deduction/payment_entry_deduction.py @@ -1,8 +1,6 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and contributors # For license information, please see license.txt -from __future__ import unicode_literals from frappe.model.document import Document diff --git a/erpnext/accounts/doctype/payment_entry_reference/payment_entry_reference.json b/erpnext/accounts/doctype/payment_entry_reference/payment_entry_reference.json index 43eb0b6e2aa..8961167f018 100644 --- a/erpnext/accounts/doctype/payment_entry_reference/payment_entry_reference.json +++ b/erpnext/accounts/doctype/payment_entry_reference/payment_entry_reference.json @@ -93,6 +93,7 @@ "options": "Payment Term" }, { + "depends_on": "exchange_gain_loss", "fieldname": "exchange_gain_loss", "fieldtype": "Currency", "label": "Exchange Gain/Loss", @@ -103,7 +104,7 @@ "index_web_pages_for_search": 1, "istable": 1, "links": [], - "modified": "2021-04-21 13:30:11.605388", + "modified": "2021-09-26 17:06:55.597389", "modified_by": "Administrator", "module": "Accounts", "name": "Payment Entry Reference", diff --git a/erpnext/accounts/doctype/payment_entry_reference/payment_entry_reference.py b/erpnext/accounts/doctype/payment_entry_reference/payment_entry_reference.py index a686f495cda..fc1cad9ad67 100644 --- a/erpnext/accounts/doctype/payment_entry_reference/payment_entry_reference.py +++ b/erpnext/accounts/doctype/payment_entry_reference/payment_entry_reference.py @@ -1,8 +1,6 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and contributors # For license information, please see license.txt -from __future__ import unicode_literals from frappe.model.document import Document diff --git a/erpnext/accounts/doctype/payment_gateway_account/payment_gateway_account.py b/erpnext/accounts/doctype/payment_gateway_account/payment_gateway_account.py index 1d8a8ac5e19..25dc4e6a60d 100644 --- a/erpnext/accounts/doctype/payment_gateway_account/payment_gateway_account.py +++ b/erpnext/accounts/doctype/payment_gateway_account/payment_gateway_account.py @@ -1,8 +1,6 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and contributors # For license information, please see license.txt -from __future__ import unicode_literals import frappe from frappe.model.document import Document diff --git a/erpnext/accounts/doctype/payment_gateway_account/payment_gateway_account_dashboard.py b/erpnext/accounts/doctype/payment_gateway_account/payment_gateway_account_dashboard.py index 2edc1a1590b..39968922417 100644 --- a/erpnext/accounts/doctype/payment_gateway_account/payment_gateway_account_dashboard.py +++ b/erpnext/accounts/doctype/payment_gateway_account/payment_gateway_account_dashboard.py @@ -1,6 +1,3 @@ -from __future__ import unicode_literals - - def get_data(): return { 'fieldname': 'payment_gateway_account', diff --git a/erpnext/accounts/doctype/payment_gateway_account/test_payment_gateway_account.py b/erpnext/accounts/doctype/payment_gateway_account/test_payment_gateway_account.py index f76aa4a80f8..1895c12ad7c 100644 --- a/erpnext/accounts/doctype/payment_gateway_account/test_payment_gateway_account.py +++ b/erpnext/accounts/doctype/payment_gateway_account/test_payment_gateway_account.py @@ -1,7 +1,5 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors # See license.txt -from __future__ import unicode_literals import unittest diff --git a/erpnext/accounts/doctype/payment_order/payment_order.js b/erpnext/accounts/doctype/payment_order/payment_order.js index aa373bc2fcc..9074defa577 100644 --- a/erpnext/accounts/doctype/payment_order/payment_order.js +++ b/erpnext/accounts/doctype/payment_order/payment_order.js @@ -10,6 +10,9 @@ frappe.ui.form.on('Payment Order', { } } }); + + frm.set_df_property('references', 'cannot_add_rows', true); + frm.set_df_property('references', 'cannot_delete_rows', true); }, refresh: function(frm) { if (frm.doc.docstatus == 0) { diff --git a/erpnext/accounts/doctype/payment_order/payment_order.py b/erpnext/accounts/doctype/payment_order/payment_order.py index e9b5ad9dc4d..50a58b8a0ab 100644 --- a/erpnext/accounts/doctype/payment_order/payment_order.py +++ b/erpnext/accounts/doctype/payment_order/payment_order.py @@ -1,8 +1,6 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2018, Frappe Technologies Pvt. Ltd. and contributors # For license information, please see license.txt -from __future__ import unicode_literals import frappe from frappe import _ diff --git a/erpnext/accounts/doctype/payment_order/payment_order_dashboard.py b/erpnext/accounts/doctype/payment_order/payment_order_dashboard.py index d9262be9b86..37bbaec33d9 100644 --- a/erpnext/accounts/doctype/payment_order/payment_order_dashboard.py +++ b/erpnext/accounts/doctype/payment_order/payment_order_dashboard.py @@ -1,6 +1,3 @@ -from __future__ import unicode_literals - - def get_data(): return { 'fieldname': 'payment_order', diff --git a/erpnext/accounts/doctype/payment_order/test_payment_order.py b/erpnext/accounts/doctype/payment_order/test_payment_order.py index 6414473346b..3f4d89b4eaf 100644 --- a/erpnext/accounts/doctype/payment_order/test_payment_order.py +++ b/erpnext/accounts/doctype/payment_order/test_payment_order.py @@ -1,7 +1,5 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2018, Frappe Technologies Pvt. Ltd. and Contributors # See license.txt -from __future__ import unicode_literals import unittest diff --git a/erpnext/accounts/doctype/payment_order_reference/payment_order_reference.py b/erpnext/accounts/doctype/payment_order_reference/payment_order_reference.py index 4bb98a3b61a..94704fcd16e 100644 --- a/erpnext/accounts/doctype/payment_order_reference/payment_order_reference.py +++ b/erpnext/accounts/doctype/payment_order_reference/payment_order_reference.py @@ -1,8 +1,6 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2018, Frappe Technologies Pvt. Ltd. and contributors # For license information, please see license.txt -from __future__ import unicode_literals from frappe.model.document import Document diff --git a/erpnext/accounts/doctype/payment_reconciliation/payment_reconciliation.js b/erpnext/accounts/doctype/payment_reconciliation/payment_reconciliation.js index b1f3e6fd014..ad5a84094ea 100644 --- a/erpnext/accounts/doctype/payment_reconciliation/payment_reconciliation.js +++ b/erpnext/accounts/doctype/payment_reconciliation/payment_reconciliation.js @@ -4,9 +4,14 @@ frappe.provide("erpnext.accounts"); erpnext.accounts.PaymentReconciliationController = class PaymentReconciliationController extends frappe.ui.form.Controller { onload() { - var me = this; + const default_company = frappe.defaults.get_default('company'); + this.frm.set_value('company', default_company); - this.frm.set_query("party_type", function() { + this.frm.set_value('party_type', ''); + this.frm.set_value('party', ''); + this.frm.set_value('receivable_payable_account', ''); + + this.frm.set_query("party_type", () => { return { "filters": { "name": ["in", Object.keys(frappe.boot.party_account_types)], @@ -14,133 +19,149 @@ erpnext.accounts.PaymentReconciliationController = class PaymentReconciliationCo } }); - this.frm.set_query('receivable_payable_account', function() { - check_mandatory(me.frm); + this.frm.set_query('receivable_payable_account', () => { return { filters: { - "company": me.frm.doc.company, + "company": this.frm.doc.company, "is_group": 0, - "account_type": frappe.boot.party_account_types[me.frm.doc.party_type] + "account_type": frappe.boot.party_account_types[this.frm.doc.party_type] } }; }); - this.frm.set_query('bank_cash_account', function() { - check_mandatory(me.frm, true); + this.frm.set_query('bank_cash_account', () => { return { filters:[ - ['Account', 'company', '=', me.frm.doc.company], + ['Account', 'company', '=', this.frm.doc.company], ['Account', 'is_group', '=', 0], ['Account', 'account_type', 'in', ['Bank', 'Cash']] ] }; }); - - this.frm.set_value('party_type', ''); - this.frm.set_value('party', ''); - this.frm.set_value('receivable_payable_account', ''); - - var check_mandatory = (frm, only_company=false) => { - var title = __("Mandatory"); - if (only_company && !frm.doc.company) { - frappe.throw({message: __("Please Select a Company First"), title: title}); - } else if (!frm.doc.company || !frm.doc.party_type) { - frappe.throw({message: __("Please Select Both Company and Party Type First"), title: title}); - } - }; } refresh() { this.frm.disable_save(); + this.frm.set_df_property('invoices', 'cannot_delete_rows', true); + this.frm.set_df_property('payments', 'cannot_delete_rows', true); + this.frm.set_df_property('allocation', 'cannot_delete_rows', true); + + this.frm.set_df_property('invoices', 'cannot_add_rows', true); + this.frm.set_df_property('payments', 'cannot_add_rows', true); + this.frm.set_df_property('allocation', 'cannot_add_rows', true); + + if (this.frm.doc.receivable_payable_account) { this.frm.add_custom_button(__('Get Unreconciled Entries'), () => this.frm.trigger("get_unreconciled_entries") ); + this.frm.change_custom_button_type('Get Unreconciled Entries', null, 'primary'); } if (this.frm.doc.invoices.length && this.frm.doc.payments.length) { this.frm.add_custom_button(__('Allocate'), () => this.frm.trigger("allocate") ); + this.frm.change_custom_button_type('Allocate', null, 'primary'); + this.frm.change_custom_button_type('Get Unreconciled Entries', null, 'default'); } if (this.frm.doc.allocation.length) { this.frm.add_custom_button(__('Reconcile'), () => this.frm.trigger("reconcile") ); + this.frm.change_custom_button_type('Reconcile', null, 'primary'); + this.frm.change_custom_button_type('Get Unreconciled Entries', null, 'default'); + this.frm.change_custom_button_type('Allocate', null, 'default'); } } company() { - var me = this; + this.frm.set_value('party', ''); this.frm.set_value('receivable_payable_account', ''); - me.frm.clear_table("allocation"); - me.frm.clear_table("invoices"); - me.frm.clear_table("payments"); - me.frm.refresh_fields(); - me.frm.trigger('party'); + } + + party_type() { + this.frm.set_value('party', ''); } party() { - var me = this; - if (!me.frm.doc.receivable_payable_account && me.frm.doc.party_type && me.frm.doc.party) { + this.frm.set_value('receivable_payable_account', ''); + this.frm.trigger("clear_child_tables"); + + if (!this.frm.doc.receivable_payable_account && this.frm.doc.party_type && this.frm.doc.party) { return frappe.call({ method: "erpnext.accounts.party.get_party_account", args: { - company: me.frm.doc.company, - party_type: me.frm.doc.party_type, - party: me.frm.doc.party + company: this.frm.doc.company, + party_type: this.frm.doc.party_type, + party: this.frm.doc.party }, - callback: function(r) { + callback: (r) => { if (!r.exc && r.message) { - me.frm.set_value("receivable_payable_account", r.message); + this.frm.set_value("receivable_payable_account", r.message); } - me.frm.refresh(); + this.frm.refresh(); + } }); } } + receivable_payable_account() { + this.frm.trigger("clear_child_tables"); + this.frm.refresh(); + } + + clear_child_tables() { + this.frm.clear_table("invoices"); + this.frm.clear_table("payments"); + this.frm.clear_table("allocation"); + this.frm.refresh_fields(); + } + get_unreconciled_entries() { - var me = this; + this.frm.clear_table("allocation"); return this.frm.call({ - doc: me.frm.doc, + doc: this.frm.doc, method: 'get_unreconciled_entries', - callback: function(r, rt) { - if (!(me.frm.doc.payments.length || me.frm.doc.invoices.length)) { - frappe.throw({message: __("No invoice and payment records found for this party")}); + callback: () => { + if (!(this.frm.doc.payments.length || this.frm.doc.invoices.length)) { + frappe.throw({message: __("No Unreconciled Invoices and Payments found for this party and account")}); + } else if (!(this.frm.doc.invoices.length)) { + frappe.throw({message: __("No Outstanding Invoices found for this party")}); + } else if (!(this.frm.doc.payments.length)) { + frappe.throw({message: __("No Unreconciled Payments found for this party")}); } - me.frm.refresh(); + this.frm.refresh(); } }); } allocate() { - var me = this; - let payments = me.frm.fields_dict.payments.grid.get_selected_children(); + let payments = this.frm.fields_dict.payments.grid.get_selected_children(); if (!(payments.length)) { - payments = me.frm.doc.payments; + payments = this.frm.doc.payments; } - let invoices = me.frm.fields_dict.invoices.grid.get_selected_children(); + let invoices = this.frm.fields_dict.invoices.grid.get_selected_children(); if (!(invoices.length)) { - invoices = me.frm.doc.invoices; + invoices = this.frm.doc.invoices; } - return me.frm.call({ - doc: me.frm.doc, + return this.frm.call({ + doc: this.frm.doc, method: 'allocate_entries', args: { payments: payments, invoices: invoices }, - callback: function() { - me.frm.refresh(); + callback: () => { + this.frm.refresh(); } }); } reconcile() { - var me = this; - var show_dialog = me.frm.doc.allocation.filter(d => d.difference_amount && !d.difference_account); + var show_dialog = this.frm.doc.allocation.filter(d => d.difference_amount && !d.difference_account); if (show_dialog && show_dialog.length) { @@ -172,10 +193,10 @@ erpnext.accounts.PaymentReconciliationController = class PaymentReconciliationCo label: __("Difference Account"), fieldname: 'difference_account', reqd: 1, - get_query: function() { + get_query: () => { return { filters: { - company: me.frm.doc.company, + company: this.frm.doc.company, is_group: 0 } } @@ -189,7 +210,7 @@ erpnext.accounts.PaymentReconciliationController = class PaymentReconciliationCo }] }, ], - primary_action: function() { + primary_action: () => { const args = dialog.get_values()["allocation"]; args.forEach(d => { @@ -197,7 +218,7 @@ erpnext.accounts.PaymentReconciliationController = class PaymentReconciliationCo "difference_account", d.difference_account); }); - me.reconcile_payment_entries(); + this.reconcile_payment_entries(); dialog.hide(); }, primary_action_label: __('Reconcile Entries') @@ -223,15 +244,12 @@ erpnext.accounts.PaymentReconciliationController = class PaymentReconciliationCo } reconcile_payment_entries() { - var me = this; - return this.frm.call({ - doc: me.frm.doc, + doc: this.frm.doc, method: 'reconcile', - callback: function(r, rt) { - me.frm.clear_table("allocation"); - me.frm.refresh_fields(); - me.frm.refresh(); + callback: () => { + this.frm.clear_table("allocation"); + this.frm.refresh(); } }); } diff --git a/erpnext/accounts/doctype/payment_reconciliation/payment_reconciliation.json b/erpnext/accounts/doctype/payment_reconciliation/payment_reconciliation.json index 9023b3646f2..eb0c20f92d9 100644 --- a/erpnext/accounts/doctype/payment_reconciliation/payment_reconciliation.json +++ b/erpnext/accounts/doctype/payment_reconciliation/payment_reconciliation.json @@ -12,15 +12,16 @@ "receivable_payable_account", "col_break1", "from_invoice_date", - "to_invoice_date", - "minimum_invoice_amount", - "maximum_invoice_amount", - "invoice_limit", - "column_break_13", "from_payment_date", - "to_payment_date", + "minimum_invoice_amount", "minimum_payment_amount", + "column_break_11", + "to_invoice_date", + "to_payment_date", + "maximum_invoice_amount", "maximum_payment_amount", + "column_break_13", + "invoice_limit", "payment_limit", "bank_cash_account", "sec_break1", @@ -79,6 +80,7 @@ }, { "depends_on": "eval:(doc.payments).length || (doc.invoices).length", + "description": "If you need to reconcile particular transactions against each other, then please select accordingly. If not, all the transactions will be allocated in FIFO order.", "fieldname": "sec_break1", "fieldtype": "Section Break", "label": "Unreconciled Entries" @@ -163,6 +165,7 @@ "label": "Maximum Payment Amount" }, { + "description": "System will fetch all the entries if limit value is zero.", "fieldname": "payment_limit", "fieldtype": "Int", "label": "Payment Limit" @@ -171,13 +174,17 @@ "fieldname": "maximum_invoice_amount", "fieldtype": "Currency", "label": "Maximum Invoice Amount" + }, + { + "fieldname": "column_break_11", + "fieldtype": "Column Break" } ], "hide_toolbar": 1, "icon": "icon-resize-horizontal", "issingle": 1, "links": [], - "modified": "2021-08-30 13:05:51.977861", + "modified": "2021-10-04 20:27:11.114194", "modified_by": "Administrator", "module": "Accounts", "name": "Payment Reconciliation", diff --git a/erpnext/accounts/doctype/payment_reconciliation/payment_reconciliation.py b/erpnext/accounts/doctype/payment_reconciliation/payment_reconciliation.py index 9de79aee58a..548571d1d76 100644 --- a/erpnext/accounts/doctype/payment_reconciliation/payment_reconciliation.py +++ b/erpnext/accounts/doctype/payment_reconciliation/payment_reconciliation.py @@ -1,7 +1,6 @@ # Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors # For license information, please see license.txt -from __future__ import unicode_literals import frappe from frappe import _, msgprint diff --git a/erpnext/accounts/doctype/payment_reconciliation_allocation/payment_reconciliation_allocation.json b/erpnext/accounts/doctype/payment_reconciliation_allocation/payment_reconciliation_allocation.json index 36535014320..6a21692c6ac 100644 --- a/erpnext/accounts/doctype/payment_reconciliation_allocation/payment_reconciliation_allocation.json +++ b/erpnext/accounts/doctype/payment_reconciliation_allocation/payment_reconciliation_allocation.json @@ -7,14 +7,15 @@ "field_order": [ "reference_type", "reference_name", + "reference_row", "column_break_3", "invoice_type", "invoice_number", "section_break_6", "allocated_amount", "unreconciled_amount", - "amount", "column_break_8", + "amount", "is_advance", "section_break_5", "difference_amount", @@ -121,11 +122,18 @@ "label": "Amount", "options": "Currency", "read_only": 1 + }, + { + "fieldname": "reference_row", + "fieldtype": "Data", + "hidden": 1, + "label": "Reference Row", + "read_only": 1 } ], "istable": 1, "links": [], - "modified": "2021-08-30 10:58:42.665107", + "modified": "2021-10-06 11:48:59.616562", "modified_by": "Administrator", "module": "Accounts", "name": "Payment Reconciliation Allocation", diff --git a/erpnext/accounts/doctype/payment_reconciliation_invoice/payment_reconciliation_invoice.py b/erpnext/accounts/doctype/payment_reconciliation_invoice/payment_reconciliation_invoice.py index 5ac1855c030..7665b75ff0f 100644 --- a/erpnext/accounts/doctype/payment_reconciliation_invoice/payment_reconciliation_invoice.py +++ b/erpnext/accounts/doctype/payment_reconciliation_invoice/payment_reconciliation_invoice.py @@ -1,7 +1,6 @@ # Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors and contributors # For license information, please see license.txt -from __future__ import unicode_literals from frappe.model.document import Document diff --git a/erpnext/accounts/doctype/payment_reconciliation_payment/payment_reconciliation_payment.py b/erpnext/accounts/doctype/payment_reconciliation_payment/payment_reconciliation_payment.py index 78c84ff5a6a..c0e3fd641ad 100644 --- a/erpnext/accounts/doctype/payment_reconciliation_payment/payment_reconciliation_payment.py +++ b/erpnext/accounts/doctype/payment_reconciliation_payment/payment_reconciliation_payment.py @@ -1,7 +1,6 @@ # Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors and contributors # For license information, please see license.txt -from __future__ import unicode_literals from frappe.model.document import Document diff --git a/erpnext/accounts/doctype/payment_request/payment_request.py b/erpnext/accounts/doctype/payment_request/payment_request.py index 2c967497d59..6a84a65e713 100644 --- a/erpnext/accounts/doctype/payment_request/payment_request.py +++ b/erpnext/accounts/doctype/payment_request/payment_request.py @@ -1,8 +1,6 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and contributors # For license information, please see license.txt -from __future__ import unicode_literals import json @@ -550,10 +548,14 @@ def make_payment_order(source_name, target_doc=None): return doclist -def validate_payment(doc, method=""): - if not frappe.db.has_column(doc.reference_doctype, 'status'): +def validate_payment(doc, method=None): + if doc.reference_doctype != "Payment Request" or ( + frappe.db.get_value(doc.reference_doctype, doc.reference_docname, 'status') + != "Paid" + ): return - status = frappe.db.get_value(doc.reference_doctype, doc.reference_docname, 'status') - if status == 'Paid': - frappe.throw(_("The Payment Request {0} is already paid, cannot process payment twice").format(doc.reference_docname)) \ No newline at end of file + frappe.throw( + _("The Payment Request {0} is already paid, cannot process payment twice") + .format(doc.reference_docname) + ) diff --git a/erpnext/accounts/doctype/payment_request/test_payment_request.py b/erpnext/accounts/doctype/payment_request/test_payment_request.py index c97c873fc4e..f679ccfe4ff 100644 --- a/erpnext/accounts/doctype/payment_request/test_payment_request.py +++ b/erpnext/accounts/doctype/payment_request/test_payment_request.py @@ -1,7 +1,5 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors # See license.txt -from __future__ import unicode_literals import unittest diff --git a/erpnext/accounts/doctype/payment_schedule/payment_schedule.py b/erpnext/accounts/doctype/payment_schedule/payment_schedule.py index 33d5efa10e3..33e261f0efd 100644 --- a/erpnext/accounts/doctype/payment_schedule/payment_schedule.py +++ b/erpnext/accounts/doctype/payment_schedule/payment_schedule.py @@ -1,8 +1,6 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2017, Frappe Technologies Pvt. Ltd. and contributors # For license information, please see license.txt -from __future__ import unicode_literals from frappe.model.document import Document diff --git a/erpnext/accounts/doctype/payment_term/payment_term.py b/erpnext/accounts/doctype/payment_term/payment_term.py index a04c183bedc..956c2b13fd9 100644 --- a/erpnext/accounts/doctype/payment_term/payment_term.py +++ b/erpnext/accounts/doctype/payment_term/payment_term.py @@ -1,8 +1,6 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2017, Frappe Technologies Pvt. Ltd. and contributors # For license information, please see license.txt -from __future__ import unicode_literals from frappe.model.document import Document diff --git a/erpnext/accounts/doctype/payment_term/payment_term_dashboard.py b/erpnext/accounts/doctype/payment_term/payment_term_dashboard.py index d146fcdee38..ac80b794bab 100644 --- a/erpnext/accounts/doctype/payment_term/payment_term_dashboard.py +++ b/erpnext/accounts/doctype/payment_term/payment_term_dashboard.py @@ -1,5 +1,3 @@ -from __future__ import unicode_literals - from frappe import _ diff --git a/erpnext/accounts/doctype/payment_term/test_payment_term.py b/erpnext/accounts/doctype/payment_term/test_payment_term.py index bc0645f9a62..820610c17c2 100644 --- a/erpnext/accounts/doctype/payment_term/test_payment_term.py +++ b/erpnext/accounts/doctype/payment_term/test_payment_term.py @@ -1,7 +1,5 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2017, Frappe Technologies Pvt. Ltd. and Contributors # See license.txt -from __future__ import unicode_literals import unittest diff --git a/erpnext/accounts/doctype/payment_terms_template/payment_terms_template.py b/erpnext/accounts/doctype/payment_terms_template/payment_terms_template.py index 35685911324..3a6999c5799 100644 --- a/erpnext/accounts/doctype/payment_terms_template/payment_terms_template.py +++ b/erpnext/accounts/doctype/payment_terms_template/payment_terms_template.py @@ -1,8 +1,6 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2017, Frappe Technologies Pvt. Ltd. and contributors # For license information, please see license.txt -from __future__ import unicode_literals import frappe from frappe import _ diff --git a/erpnext/accounts/doctype/payment_terms_template/payment_terms_template_dashboard.py b/erpnext/accounts/doctype/payment_terms_template/payment_terms_template_dashboard.py index 5c8cb4fbdc1..2cf7a6cf7a2 100644 --- a/erpnext/accounts/doctype/payment_terms_template/payment_terms_template_dashboard.py +++ b/erpnext/accounts/doctype/payment_terms_template/payment_terms_template_dashboard.py @@ -1,5 +1,3 @@ -from __future__ import unicode_literals - from frappe import _ diff --git a/erpnext/accounts/doctype/payment_terms_template/test_payment_terms_template.py b/erpnext/accounts/doctype/payment_terms_template/test_payment_terms_template.py index 2052a5093d2..8529ef5c3d5 100644 --- a/erpnext/accounts/doctype/payment_terms_template/test_payment_terms_template.py +++ b/erpnext/accounts/doctype/payment_terms_template/test_payment_terms_template.py @@ -1,7 +1,5 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2017, Frappe Technologies Pvt. Ltd. and Contributors # See license.txt -from __future__ import unicode_literals import unittest diff --git a/erpnext/accounts/doctype/payment_terms_template_detail/payment_terms_template_detail.py b/erpnext/accounts/doctype/payment_terms_template_detail/payment_terms_template_detail.py index c857a88b9f5..710988bdf0e 100644 --- a/erpnext/accounts/doctype/payment_terms_template_detail/payment_terms_template_detail.py +++ b/erpnext/accounts/doctype/payment_terms_template_detail/payment_terms_template_detail.py @@ -1,8 +1,6 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2017, Frappe Technologies Pvt. Ltd. and contributors # For license information, please see license.txt -from __future__ import unicode_literals from frappe.model.document import Document diff --git a/erpnext/accounts/doctype/period_closing_voucher/__init__.py b/erpnext/accounts/doctype/period_closing_voucher/__init__.py index baffc488252..e69de29bb2d 100644 --- a/erpnext/accounts/doctype/period_closing_voucher/__init__.py +++ b/erpnext/accounts/doctype/period_closing_voucher/__init__.py @@ -1 +0,0 @@ -from __future__ import unicode_literals diff --git a/erpnext/accounts/doctype/period_closing_voucher/period_closing_voucher.py b/erpnext/accounts/doctype/period_closing_voucher/period_closing_voucher.py index 888bf9fd940..d0e555e40c7 100644 --- a/erpnext/accounts/doctype/period_closing_voucher/period_closing_voucher.py +++ b/erpnext/accounts/doctype/period_closing_voucher/period_closing_voucher.py @@ -1,7 +1,6 @@ # Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors # License: GNU General Public License v3. See license.txt -from __future__ import unicode_literals import frappe from frappe import _ @@ -89,9 +88,10 @@ class PeriodClosingVoucher(AccountsController): 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": acc.cost_center or company_cost_center, + "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, diff --git a/erpnext/accounts/doctype/period_closing_voucher/test_period_closing_voucher.py b/erpnext/accounts/doctype/period_closing_voucher/test_period_closing_voucher.py index 2d417a4cfba..030b4caf7ca 100644 --- a/erpnext/accounts/doctype/period_closing_voucher/test_period_closing_voucher.py +++ b/erpnext/accounts/doctype/period_closing_voucher/test_period_closing_voucher.py @@ -2,7 +2,6 @@ # License: GNU General Public License v3. See license.txt -from __future__ import unicode_literals import unittest @@ -67,8 +66,8 @@ class TestPeriodClosingVoucher(unittest.TestCase): company = create_company() surplus_account = create_account() - cost_center1 = create_cost_center("Test Cost Center 1") - cost_center2 = create_cost_center("Test Cost Center 2") + cost_center1 = create_cost_center("Main") + cost_center2 = create_cost_center("Western Branch") create_sales_invoice( company=company, @@ -87,7 +86,10 @@ class TestPeriodClosingVoucher(unittest.TestCase): debit_to="Debtors - TPC" ) - pcv = self.make_period_closing_voucher() + pcv = self.make_period_closing_voucher(submit=False) + pcv.cost_center_wise_pnl = 1 + pcv.save() + pcv.submit() surplus_account = pcv.closing_account_head expected_gle = ( @@ -150,7 +152,7 @@ class TestPeriodClosingVoucher(unittest.TestCase): self.assertEqual(pcv_gle, expected_gle) - def make_period_closing_voucher(self): + def make_period_closing_voucher(self, submit=True): surplus_account = create_account() cost_center = create_cost_center("Test Cost Center 1") pcv = frappe.get_doc({ @@ -164,7 +166,8 @@ class TestPeriodClosingVoucher(unittest.TestCase): "remarks": "test" }) pcv.insert() - pcv.submit() + if submit: + pcv.submit() return pcv diff --git a/erpnext/accounts/doctype/pos_closing_entry/pos_closing_entry.json b/erpnext/accounts/doctype/pos_closing_entry/pos_closing_entry.json index 4d6e4a2ba07..d6e35c6a50d 100644 --- a/erpnext/accounts/doctype/pos_closing_entry/pos_closing_entry.json +++ b/erpnext/accounts/doctype/pos_closing_entry/pos_closing_entry.json @@ -180,8 +180,7 @@ "fieldname": "pos_transactions", "fieldtype": "Table", "label": "POS Transactions", - "options": "POS Invoice Reference", - "reqd": 1 + "options": "POS Invoice Reference" }, { "fieldname": "pos_opening_entry", @@ -229,7 +228,7 @@ "link_fieldname": "pos_closing_entry" } ], - "modified": "2021-05-05 16:59:49.723261", + "modified": "2021-10-20 16:19:25.340565", "modified_by": "Administrator", "module": "Accounts", "name": "POS Closing Entry", diff --git a/erpnext/accounts/doctype/pos_closing_entry/pos_closing_entry.py b/erpnext/accounts/doctype/pos_closing_entry/pos_closing_entry.py index 896ebdfd5e6..07059cb7aa3 100644 --- a/erpnext/accounts/doctype/pos_closing_entry/pos_closing_entry.py +++ b/erpnext/accounts/doctype/pos_closing_entry/pos_closing_entry.py @@ -1,8 +1,6 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2018, Frappe Technologies Pvt. Ltd. and contributors # For license information, please see license.txt -from __future__ import unicode_literals import frappe from frappe import _ diff --git a/erpnext/accounts/doctype/pos_closing_entry/test_pos_closing_entry.py b/erpnext/accounts/doctype/pos_closing_entry/test_pos_closing_entry.py index 44c87d6e41b..626bee0b496 100644 --- a/erpnext/accounts/doctype/pos_closing_entry/test_pos_closing_entry.py +++ b/erpnext/accounts/doctype/pos_closing_entry/test_pos_closing_entry.py @@ -1,7 +1,5 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2018, Frappe Technologies Pvt. Ltd. and Contributors # See license.txt -from __future__ import unicode_literals import unittest diff --git a/erpnext/accounts/doctype/pos_closing_entry_detail/pos_closing_entry_detail.py b/erpnext/accounts/doctype/pos_closing_entry_detail/pos_closing_entry_detail.py index 4293abdfdc1..2e34e44c92d 100644 --- a/erpnext/accounts/doctype/pos_closing_entry_detail/pos_closing_entry_detail.py +++ b/erpnext/accounts/doctype/pos_closing_entry_detail/pos_closing_entry_detail.py @@ -1,8 +1,6 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2018, Frappe Technologies Pvt. Ltd. and contributors # For license information, please see license.txt -from __future__ import unicode_literals from frappe.model.document import Document diff --git a/erpnext/accounts/doctype/pos_closing_entry_taxes/pos_closing_entry_taxes.py b/erpnext/accounts/doctype/pos_closing_entry_taxes/pos_closing_entry_taxes.py index 74cf7540311..cfedeb3a9ab 100644 --- a/erpnext/accounts/doctype/pos_closing_entry_taxes/pos_closing_entry_taxes.py +++ b/erpnext/accounts/doctype/pos_closing_entry_taxes/pos_closing_entry_taxes.py @@ -1,8 +1,6 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2018, Frappe Technologies Pvt. Ltd. and contributors # For license information, please see license.txt -from __future__ import unicode_literals from frappe.model.document import Document diff --git a/erpnext/accounts/doctype/pos_customer_group/pos_customer_group.py b/erpnext/accounts/doctype/pos_customer_group/pos_customer_group.py index 570eb9ea177..5e532ae560b 100644 --- a/erpnext/accounts/doctype/pos_customer_group/pos_customer_group.py +++ b/erpnext/accounts/doctype/pos_customer_group/pos_customer_group.py @@ -1,8 +1,6 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and contributors # For license information, please see license.txt -from __future__ import unicode_literals from frappe.model.document import Document diff --git a/erpnext/accounts/doctype/pos_field/pos_field.py b/erpnext/accounts/doctype/pos_field/pos_field.py index 00faebb7abb..4ef8827421f 100644 --- a/erpnext/accounts/doctype/pos_field/pos_field.py +++ b/erpnext/accounts/doctype/pos_field/pos_field.py @@ -1,8 +1,6 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2019, Frappe Technologies Pvt. Ltd. and contributors # For license information, please see license.txt -from __future__ import unicode_literals # import frappe from frappe.model.document import Document diff --git a/erpnext/accounts/doctype/pos_invoice/pos_invoice.py b/erpnext/accounts/doctype/pos_invoice/pos_invoice.py index d6e41e6f90d..0d6404c3245 100644 --- a/erpnext/accounts/doctype/pos_invoice/pos_invoice.py +++ b/erpnext/accounts/doctype/pos_invoice/pos_invoice.py @@ -1,13 +1,10 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors and contributors # For license information, please see license.txt -from __future__ import unicode_literals import frappe from frappe import _ from frappe.utils import cint, flt, get_link_to_form, getdate, nowdate -from six import iteritems from erpnext.accounts.doctype.loyalty_program.loyalty_program import validate_loyalty_points from erpnext.accounts.doctype.payment_request.payment_request import make_payment_request @@ -40,6 +37,7 @@ class POSInvoice(SalesInvoice): self.validate_change_amount() self.validate_change_account() self.validate_item_cost_centers() + self.validate_warehouse() self.validate_serialised_or_batched_item() self.validate_stock_availablility() self.validate_return_items_qty() @@ -365,7 +363,7 @@ class POSInvoice(SalesInvoice): for item in self.get("items"): if item.get('item_code'): profile_details = get_pos_profile_item_details(profile.get("company"), frappe._dict(item.as_dict()), profile) - for fname, val in iteritems(profile_details): + for fname, val in profile_details.items(): if (not for_validate) or (for_validate and not item.get(fname)): item.set(fname, val) @@ -525,9 +523,8 @@ def make_sales_return(source_name, target_doc=None): def make_merge_log(invoices): import json - from six import string_types - if isinstance(invoices, string_types): + if isinstance(invoices, str): invoices = json.loads(invoices) if len(invoices) == 0: diff --git a/erpnext/accounts/doctype/pos_invoice/test_pos_invoice.py b/erpnext/accounts/doctype/pos_invoice/test_pos_invoice.py index e6e0dd238f0..66963335376 100644 --- a/erpnext/accounts/doctype/pos_invoice/test_pos_invoice.py +++ b/erpnext/accounts/doctype/pos_invoice/test_pos_invoice.py @@ -1,7 +1,5 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2020, Frappe Technologies Pvt. Ltd. and Contributors # See license.txt -from __future__ import unicode_literals import copy import unittest diff --git a/erpnext/accounts/doctype/pos_invoice_item/pos_invoice_item.py b/erpnext/accounts/doctype/pos_invoice_item/pos_invoice_item.py index 99e471991c3..7e3ae82a8be 100644 --- a/erpnext/accounts/doctype/pos_invoice_item/pos_invoice_item.py +++ b/erpnext/accounts/doctype/pos_invoice_item/pos_invoice_item.py @@ -1,8 +1,6 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2020, Frappe Technologies Pvt. Ltd. and contributors # For license information, please see license.txt -from __future__ import unicode_literals # import frappe from frappe.model.document import Document diff --git a/erpnext/accounts/doctype/pos_invoice_merge_log/pos_invoice_merge_log.js b/erpnext/accounts/doctype/pos_invoice_merge_log/pos_invoice_merge_log.js index 2f8081b95ce..73c6290d7b0 100644 --- a/erpnext/accounts/doctype/pos_invoice_merge_log/pos_invoice_merge_log.js +++ b/erpnext/accounts/doctype/pos_invoice_merge_log/pos_invoice_merge_log.js @@ -4,7 +4,7 @@ frappe.ui.form.on('POS Invoice Merge Log', { setup: function(frm) { frm.set_query("pos_invoice", "pos_invoices", doc => { - return{ + return { filters: { 'docstatus': 1, 'customer': doc.customer, @@ -12,5 +12,10 @@ frappe.ui.form.on('POS Invoice Merge Log', { } } }); + }, + + merge_invoices_based_on: function(frm) { + frm.set_value('customer', ''); + frm.set_value('customer_group', ''); } }); diff --git a/erpnext/accounts/doctype/pos_invoice_merge_log/pos_invoice_merge_log.json b/erpnext/accounts/doctype/pos_invoice_merge_log/pos_invoice_merge_log.json index da2984f05af..d7620870780 100644 --- a/erpnext/accounts/doctype/pos_invoice_merge_log/pos_invoice_merge_log.json +++ b/erpnext/accounts/doctype/pos_invoice_merge_log/pos_invoice_merge_log.json @@ -6,9 +6,11 @@ "engine": "InnoDB", "field_order": [ "posting_date", - "customer", + "merge_invoices_based_on", "column_break_3", "pos_closing_entry", + "customer", + "customer_group", "section_break_3", "pos_invoices", "references_section", @@ -88,12 +90,27 @@ "fieldtype": "Link", "label": "POS Closing Entry", "options": "POS Closing Entry" + }, + { + "fieldname": "merge_invoices_based_on", + "fieldtype": "Select", + "label": "Merge Invoices Based On", + "options": "Customer\nCustomer Group", + "reqd": 1 + }, + { + "depends_on": "eval:doc.merge_invoices_based_on == 'Customer Group'", + "fieldname": "customer_group", + "fieldtype": "Link", + "label": "Customer Group", + "mandatory_depends_on": "eval:doc.merge_invoices_based_on == 'Customer Group'", + "options": "Customer Group" } ], "index_web_pages_for_search": 1, "is_submittable": 1, "links": [], - "modified": "2020-12-01 11:53:57.267579", + "modified": "2021-09-14 11:17:19.001142", "modified_by": "Administrator", "module": "Accounts", "name": "POS Invoice Merge Log", diff --git a/erpnext/accounts/doctype/pos_invoice_merge_log/pos_invoice_merge_log.py b/erpnext/accounts/doctype/pos_invoice_merge_log/pos_invoice_merge_log.py index 0be8ca7ee69..0720d9b2e91 100644 --- a/erpnext/accounts/doctype/pos_invoice_merge_log/pos_invoice_merge_log.py +++ b/erpnext/accounts/doctype/pos_invoice_merge_log/pos_invoice_merge_log.py @@ -1,13 +1,10 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2020, Frappe Technologies Pvt. Ltd. and contributors # For license information, please see license.txt -from __future__ import unicode_literals import json import frappe -import six from frappe import _ from frappe.core.page.background_jobs.background_jobs import get_info from frappe.model.document import Document @@ -23,6 +20,9 @@ class POSInvoiceMergeLog(Document): self.validate_pos_invoice_status() def validate_customer(self): + if self.merge_invoices_based_on == 'Customer Group': + return + for d in self.pos_invoices: if d.customer != self.customer: frappe.throw(_("Row #{}: POS Invoice {} is not against customer {}").format(d.idx, d.pos_invoice, self.customer)) @@ -110,7 +110,15 @@ class POSInvoiceMergeLog(Document): def merge_pos_invoice_into(self, invoice, data): items, payments, taxes = [], [], [] + loyalty_amount_sum, loyalty_points_sum = 0, 0 + + rounding_adjustment, base_rounding_adjustment = 0, 0 + rounded_total, base_rounded_total = 0, 0 + + loyalty_amount_sum, loyalty_points_sum, idx = 0, 0, 1 + + for doc in data: map_doc(doc, invoice, table_map={ "doctype": invoice.doctype }) @@ -124,7 +132,7 @@ class POSInvoiceMergeLog(Document): found = False for i in items: if (i.item_code == item.item_code and not i.serial_no and not i.batch_no and - i.uom == item.uom and i.net_rate == item.net_rate): + i.uom == item.uom and i.net_rate == item.net_rate and i.warehouse == item.warehouse): found = True i.qty = i.qty + item.qty @@ -144,6 +152,8 @@ class POSInvoiceMergeLog(Document): found = True if not found: tax.charge_type = 'Actual' + tax.idx = idx + idx += 1 tax.included_in_print_rate = 0 tax.tax_amount = tax.tax_amount_after_discount_amount tax.base_tax_amount = tax.base_tax_amount_after_discount_amount @@ -159,6 +169,11 @@ class POSInvoiceMergeLog(Document): found = True if not found: payments.append(payment) + rounding_adjustment += doc.rounding_adjustment + rounded_total += doc.rounded_total + base_rounding_adjustment += doc.base_rounding_adjustment + base_rounded_total += doc.base_rounded_total + if loyalty_points_sum: invoice.redeem_loyalty_points = 1 @@ -168,10 +183,19 @@ class POSInvoiceMergeLog(Document): invoice.set('items', items) invoice.set('payments', payments) invoice.set('taxes', taxes) + invoice.set('rounding_adjustment',rounding_adjustment) + invoice.set('base_rounding_adjustment',base_rounding_adjustment) + invoice.set('rounded_total',rounded_total) + invoice.set('base_rounded_total',base_rounded_total) invoice.additional_discount_percentage = 0 invoice.discount_amount = 0.0 invoice.taxes_and_charges = None invoice.ignore_pricing_rule = 1 + invoice.customer = self.customer + + if self.merge_invoices_based_on == 'Customer Group': + invoice.flags.ignore_pos_profile = True + invoice.pos_profile = '' return invoice @@ -228,7 +252,7 @@ def get_all_unconsolidated_invoices(): return pos_invoices def get_invoice_customer_map(pos_invoices): - # pos_invoice_customer_map = { 'Customer 1': [{}, {}, {}], 'Custoemr 2' : [{}] } + # pos_invoice_customer_map = { 'Customer 1': [{}, {}, {}], 'Customer 2' : [{}] } pos_invoice_customer_map = {} for invoice in pos_invoices: customer = invoice.get('customer') @@ -238,7 +262,10 @@ def get_invoice_customer_map(pos_invoices): return pos_invoice_customer_map def consolidate_pos_invoices(pos_invoices=None, closing_entry=None): - invoices = pos_invoices or (closing_entry and closing_entry.get('pos_transactions')) or get_all_unconsolidated_invoices() + invoices = pos_invoices or (closing_entry and closing_entry.get('pos_transactions')) + if frappe.flags.in_test and not invoices: + invoices = get_all_unconsolidated_invoices() + invoice_by_customer = get_invoice_customer_map(invoices) if len(invoices) >= 10 and closing_entry: @@ -262,7 +289,7 @@ def unconsolidate_pos_invoices(closing_entry): def create_merge_logs(invoice_by_customer, closing_entry=None): try: - for customer, invoices in six.iteritems(invoice_by_customer): + for customer, invoices in invoice_by_customer.items(): merge_log = frappe.new_doc('POS Invoice Merge Log') merge_log.posting_date = getdate(closing_entry.get('posting_date')) if closing_entry else nowdate() merge_log.customer = customer diff --git a/erpnext/accounts/doctype/pos_invoice_merge_log/test_pos_invoice_merge_log.py b/erpnext/accounts/doctype/pos_invoice_merge_log/test_pos_invoice_merge_log.py index c531bb9f079..3555da83a40 100644 --- a/erpnext/accounts/doctype/pos_invoice_merge_log/test_pos_invoice_merge_log.py +++ b/erpnext/accounts/doctype/pos_invoice_merge_log/test_pos_invoice_merge_log.py @@ -1,7 +1,5 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2020, Frappe Technologies Pvt. Ltd. and Contributors # See license.txt -from __future__ import unicode_literals import json import unittest diff --git a/erpnext/accounts/doctype/pos_invoice_reference/pos_invoice_reference.py b/erpnext/accounts/doctype/pos_invoice_reference/pos_invoice_reference.py index 9bce082c958..c1c36f8da87 100644 --- a/erpnext/accounts/doctype/pos_invoice_reference/pos_invoice_reference.py +++ b/erpnext/accounts/doctype/pos_invoice_reference/pos_invoice_reference.py @@ -1,8 +1,6 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2020, Frappe Technologies Pvt. Ltd. and contributors # For license information, please see license.txt -from __future__ import unicode_literals # import frappe from frappe.model.document import Document diff --git a/erpnext/accounts/doctype/pos_item_group/pos_item_group.py b/erpnext/accounts/doctype/pos_item_group/pos_item_group.py index b5ff794ccc3..75fa08048d4 100644 --- a/erpnext/accounts/doctype/pos_item_group/pos_item_group.py +++ b/erpnext/accounts/doctype/pos_item_group/pos_item_group.py @@ -1,8 +1,6 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and contributors # For license information, please see license.txt -from __future__ import unicode_literals from frappe.model.document import Document diff --git a/erpnext/accounts/doctype/pos_opening_entry/pos_opening_entry.py b/erpnext/accounts/doctype/pos_opening_entry/pos_opening_entry.py index 979479ffb58..0b2e045e5a7 100644 --- a/erpnext/accounts/doctype/pos_opening_entry/pos_opening_entry.py +++ b/erpnext/accounts/doctype/pos_opening_entry/pos_opening_entry.py @@ -1,8 +1,6 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2020, Frappe Technologies Pvt. Ltd. and contributors # For license information, please see license.txt -from __future__ import unicode_literals import frappe from frappe import _ diff --git a/erpnext/accounts/doctype/pos_opening_entry/test_pos_opening_entry.py b/erpnext/accounts/doctype/pos_opening_entry/test_pos_opening_entry.py index 35a2b5835fd..105d53d00e8 100644 --- a/erpnext/accounts/doctype/pos_opening_entry/test_pos_opening_entry.py +++ b/erpnext/accounts/doctype/pos_opening_entry/test_pos_opening_entry.py @@ -1,7 +1,5 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2020, Frappe Technologies Pvt. Ltd. and Contributors # See license.txt -from __future__ import unicode_literals import unittest diff --git a/erpnext/accounts/doctype/pos_opening_entry_detail/pos_opening_entry_detail.py b/erpnext/accounts/doctype/pos_opening_entry_detail/pos_opening_entry_detail.py index be5d876a164..9108b9080b4 100644 --- a/erpnext/accounts/doctype/pos_opening_entry_detail/pos_opening_entry_detail.py +++ b/erpnext/accounts/doctype/pos_opening_entry_detail/pos_opening_entry_detail.py @@ -1,8 +1,6 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2020, Frappe Technologies Pvt. Ltd. and contributors # For license information, please see license.txt -from __future__ import unicode_literals # import frappe from frappe.model.document import Document diff --git a/erpnext/accounts/doctype/pos_payment_method/pos_payment_method.py b/erpnext/accounts/doctype/pos_payment_method/pos_payment_method.py index 851d8efde1d..589047d1d55 100644 --- a/erpnext/accounts/doctype/pos_payment_method/pos_payment_method.py +++ b/erpnext/accounts/doctype/pos_payment_method/pos_payment_method.py @@ -1,8 +1,6 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2020, Frappe Technologies Pvt. Ltd. and contributors # For license information, please see license.txt -from __future__ import unicode_literals # import frappe from frappe.model.document import Document diff --git a/erpnext/accounts/doctype/pos_profile/pos_profile.json b/erpnext/accounts/doctype/pos_profile/pos_profile.json index 8afa0abd36c..9c9f37bba27 100644 --- a/erpnext/accounts/doctype/pos_profile/pos_profile.json +++ b/erpnext/accounts/doctype/pos_profile/pos_profile.json @@ -120,6 +120,7 @@ { "fieldname": "payments", "fieldtype": "Table", + "label": "Payment Methods", "options": "POS Payment Method", "reqd": 1 }, @@ -377,7 +378,7 @@ "link_fieldname": "pos_profile" } ], - "modified": "2021-02-01 13:52:51.081311", + "modified": "2021-10-14 14:17:00.469298", "modified_by": "Administrator", "module": "Accounts", "name": "POS Profile", diff --git a/erpnext/accounts/doctype/pos_profile/pos_profile.py b/erpnext/accounts/doctype/pos_profile/pos_profile.py index b64e2eda2db..1d49c3df147 100644 --- a/erpnext/accounts/doctype/pos_profile/pos_profile.py +++ b/erpnext/accounts/doctype/pos_profile/pos_profile.py @@ -1,13 +1,11 @@ # Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors # License: GNU General Public License v3. See license.txt -from __future__ import unicode_literals import frappe from frappe import _, msgprint from frappe.model.document import Document from frappe.utils import get_link_to_form, now -from six import iteritems class POSProfile(Document): @@ -38,7 +36,7 @@ class POSProfile(Document): self.expense_account], "Cost Center": [self.cost_center], "Warehouse": [self.warehouse]} - for link_dt, dn_list in iteritems(accounts): + for link_dt, dn_list in accounts.items(): for link_dn in dn_list: if link_dn and not frappe.db.exists({"doctype": link_dt, "company": self.company, "name": link_dn}): diff --git a/erpnext/accounts/doctype/pos_profile/test_pos_profile.py b/erpnext/accounts/doctype/pos_profile/test_pos_profile.py index 83ecfb47bb5..c8cf0d2a0f1 100644 --- a/erpnext/accounts/doctype/pos_profile/test_pos_profile.py +++ b/erpnext/accounts/doctype/pos_profile/test_pos_profile.py @@ -1,7 +1,5 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors and Contributors # See license.txt -from __future__ import unicode_literals import unittest @@ -33,7 +31,9 @@ class TestPOSProfile(unittest.TestCase): frappe.db.sql("delete from `tabPOS Profile`") -def get_customers_list(pos_profile={}): +def get_customers_list(pos_profile=None): + if pos_profile is None: + pos_profile = {} cond = "1=1" customer_groups = [] if pos_profile.get('customer_groups'): diff --git a/erpnext/accounts/doctype/pos_profile_user/pos_profile_user.py b/erpnext/accounts/doctype/pos_profile_user/pos_profile_user.py index 404c4ab6296..c92d5632250 100644 --- a/erpnext/accounts/doctype/pos_profile_user/pos_profile_user.py +++ b/erpnext/accounts/doctype/pos_profile_user/pos_profile_user.py @@ -1,8 +1,6 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2017, Frappe Technologies Pvt. Ltd. and contributors # For license information, please see license.txt -from __future__ import unicode_literals from frappe.model.document import Document diff --git a/erpnext/accounts/doctype/pos_profile_user/test_pos_profile_user.py b/erpnext/accounts/doctype/pos_profile_user/test_pos_profile_user.py index dca35564082..3aafb1df32c 100644 --- a/erpnext/accounts/doctype/pos_profile_user/test_pos_profile_user.py +++ b/erpnext/accounts/doctype/pos_profile_user/test_pos_profile_user.py @@ -1,7 +1,5 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2017, Frappe Technologies Pvt. Ltd. and Contributors # See license.txt -from __future__ import unicode_literals import unittest diff --git a/erpnext/accounts/doctype/pos_search_fields/pos_search_fields.py b/erpnext/accounts/doctype/pos_search_fields/pos_search_fields.py index 32f9f9298b1..fd55dc85a7f 100644 --- a/erpnext/accounts/doctype/pos_search_fields/pos_search_fields.py +++ b/erpnext/accounts/doctype/pos_search_fields/pos_search_fields.py @@ -1,8 +1,6 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2021, Frappe Technologies Pvt. Ltd. and contributors # For license information, please see license.txt -from __future__ import unicode_literals # import frappe from frappe.model.document import Document diff --git a/erpnext/accounts/doctype/pos_settings/pos_settings.js b/erpnext/accounts/doctype/pos_settings/pos_settings.js index 9003af56a5d..7d8f3562c8c 100644 --- a/erpnext/accounts/doctype/pos_settings/pos_settings.js +++ b/erpnext/accounts/doctype/pos_settings/pos_settings.js @@ -2,11 +2,11 @@ // For license information, please see license.txt let search_fields_datatypes = ['Data', 'Link', 'Dynamic Link', 'Long Text', 'Select', 'Small Text', 'Text', 'Text Editor']; -let do_not_include_fields = ["naming_series", "item_code", "item_name", "stock_uom", "hub_sync_id", "asset_naming_series", +let do_not_include_fields = ["naming_series", "item_code", "item_name", "stock_uom", "asset_naming_series", "default_material_request_type", "valuation_method", "warranty_period", "weight_uom", "batch_number_series", "serial_no_series", "purchase_uom", "customs_tariff_number", "sales_uom", "deferred_revenue_account", "deferred_expense_account", "quality_inspection_template", "route", "slideshow", "website_image_alt", "thumbnail", - "web_long_description", "hub_sync_id"] + "web_long_description"] frappe.ui.form.on('POS Settings', { onload: function(frm) { diff --git a/erpnext/accounts/doctype/pos_settings/pos_settings.py b/erpnext/accounts/doctype/pos_settings/pos_settings.py index 5c5aaa04ed3..2adecc0859d 100644 --- a/erpnext/accounts/doctype/pos_settings/pos_settings.py +++ b/erpnext/accounts/doctype/pos_settings/pos_settings.py @@ -1,8 +1,6 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2017, Frappe Technologies Pvt. Ltd. and contributors # For license information, please see license.txt -from __future__ import unicode_literals from frappe.model.document import Document diff --git a/erpnext/accounts/doctype/pos_settings/test_pos_settings.py b/erpnext/accounts/doctype/pos_settings/test_pos_settings.py index 949fed775bf..630b30564ad 100644 --- a/erpnext/accounts/doctype/pos_settings/test_pos_settings.py +++ b/erpnext/accounts/doctype/pos_settings/test_pos_settings.py @@ -1,7 +1,5 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2017, Frappe Technologies Pvt. Ltd. and Contributors # See license.txt -from __future__ import unicode_literals import unittest diff --git a/erpnext/accounts/doctype/pricing_rule/pricing_rule.js b/erpnext/accounts/doctype/pricing_rule/pricing_rule.js index d79ad5f528f..826758245a3 100644 --- a/erpnext/accounts/doctype/pricing_rule/pricing_rule.js +++ b/erpnext/accounts/doctype/pricing_rule/pricing_rule.js @@ -38,7 +38,7 @@ frappe.ui.form.on('Pricing Rule', { refresh: function(frm) { var help_content = - ` + `
- - """.format(item_link, frappe.bold(shortage_qty)) - - message += """ -

diff --git a/erpnext/accounts/doctype/pricing_rule/pricing_rule.py b/erpnext/accounts/doctype/pricing_rule/pricing_rule.py index e5bf3b80641..ac96b045a22 100644 --- a/erpnext/accounts/doctype/pricing_rule/pricing_rule.py +++ b/erpnext/accounts/doctype/pricing_rule/pricing_rule.py @@ -2,7 +2,6 @@ # For license information, please see license.txt -from __future__ import unicode_literals import copy import json @@ -12,7 +11,6 @@ import frappe from frappe import _, throw from frappe.model.document import Document from frappe.utils import cint, flt, getdate -from six import string_types apply_on_dict = {"Item Code": "items", "Item Group": "item_groups", "Brand": "brands"} @@ -179,7 +177,7 @@ def apply_pricing_rule(args, doc=None): } """ - if isinstance(args, string_types): + if isinstance(args, str): args = json.loads(args) args = frappe._dict(args) @@ -235,7 +233,7 @@ def get_pricing_rule_for_item(args, price_list_rate=0, doc=None, for_validate=Fa get_product_discount_rule, ) - if isinstance(doc, string_types): + if isinstance(doc, str): doc = json.loads(doc) if doc: @@ -271,7 +269,7 @@ def get_pricing_rule_for_item(args, price_list_rate=0, doc=None, for_validate=Fa for pricing_rule in pricing_rules: if not pricing_rule: continue - if isinstance(pricing_rule, string_types): + if isinstance(pricing_rule, str): pricing_rule = frappe.get_cached_doc("Pricing Rule", pricing_rule) pricing_rule.apply_rule_on_other_items = get_pricing_rule_items(pricing_rule) @@ -428,7 +426,7 @@ def remove_pricing_rule_for_item(pricing_rules, item_details, item_code=None): @frappe.whitelist() def remove_pricing_rules(item_list): - if isinstance(item_list, string_types): + if isinstance(item_list, str): item_list = json.loads(item_list) out = [] diff --git a/erpnext/accounts/doctype/pricing_rule/test_pricing_rule.py b/erpnext/accounts/doctype/pricing_rule/test_pricing_rule.py index 2e2d425dab7..d8b860671f0 100644 --- a/erpnext/accounts/doctype/pricing_rule/test_pricing_rule.py +++ b/erpnext/accounts/doctype/pricing_rule/test_pricing_rule.py @@ -2,15 +2,12 @@ # License: GNU General Public License v3. See license.txt -from __future__ import unicode_literals import unittest import frappe -from frappe import MandatoryError from erpnext.accounts.doctype.sales_invoice.test_sales_invoice import create_sales_invoice -from erpnext.healthcare.doctype.lab_test_template.lab_test_template import make_item_price from erpnext.selling.doctype.sales_order.test_sales_order import make_sales_order from erpnext.stock.doctype.item.test_item import make_item from erpnext.stock.get_item_details import get_item_details @@ -546,6 +543,75 @@ class TestPricingRule(unittest.TestCase): frappe.get_doc("Item Price", {"item_code": "Water Flask"}).delete() item.delete() + def test_pricing_rule_for_different_currency(self): + make_item("Test Sanitizer Item") + + pricing_rule_record = { + "doctype": "Pricing Rule", + "title": "_Test Sanitizer Rule", + "apply_on": "Item Code", + "items": [{ + "item_code": "Test Sanitizer Item", + }], + "selling": 1, + "currency": "INR", + "rate_or_discount": "Rate", + "rate": 0, + "priority": 2, + "margin_type": "Percentage", + "margin_rate_or_amount": 0.0, + "company": "_Test Company" + } + + rule = frappe.get_doc(pricing_rule_record) + rule.rate_or_discount = 'Rate' + rule.rate = 100.0 + rule.insert() + + rule1 = frappe.get_doc(pricing_rule_record) + rule1.currency = 'USD' + rule1.rate_or_discount = 'Rate' + rule1.rate = 2.0 + rule1.priority = 1 + rule1.insert() + + args = frappe._dict({ + "item_code": "Test Sanitizer Item", + "company": "_Test Company", + "price_list": "_Test Price List", + "currency": "USD", + "doctype": "Sales Invoice", + "conversion_rate": 1, + "price_list_currency": "_Test Currency", + "plc_conversion_rate": 1, + "order_type": "Sales", + "customer": "_Test Customer", + "name": None, + "transaction_date": frappe.utils.nowdate() + }) + + details = get_item_details(args) + self.assertEqual(details.price_list_rate, 2.0) + + + args = frappe._dict({ + "item_code": "Test Sanitizer Item", + "company": "_Test Company", + "price_list": "_Test Price List", + "currency": "INR", + "doctype": "Sales Invoice", + "conversion_rate": 1, + "price_list_currency": "_Test Currency", + "plc_conversion_rate": 1, + "order_type": "Sales", + "customer": "_Test Customer", + "name": None, + "transaction_date": frappe.utils.nowdate() + }) + + details = get_item_details(args) + self.assertEqual(details.price_list_rate, 100.0) + def test_pricing_rule_for_transaction(self): make_item("Water Flask 1") frappe.delete_doc_if_exists('Pricing Rule', '_Test Pricing Rule') @@ -623,3 +689,12 @@ def delete_existing_pricing_rules(): "Pricing Rule Item Group", "Pricing Rule Brand"]: frappe.db.sql("delete from `tab{0}`".format(doctype)) + + +def make_item_price(item, price_list_name, item_price): + frappe.get_doc({ + 'doctype': 'Item Price', + 'price_list': price_list_name, + 'item_code': item, + 'price_list_rate': item_price + }).insert(ignore_permissions=True, ignore_mandatory=True) diff --git a/erpnext/accounts/doctype/pricing_rule/utils.py b/erpnext/accounts/doctype/pricing_rule/utils.py index 12b486e45eb..02bfc9defd7 100644 --- a/erpnext/accounts/doctype/pricing_rule/utils.py +++ b/erpnext/accounts/doctype/pricing_rule/utils.py @@ -3,7 +3,6 @@ # For license information, please see license.txt -from __future__ import unicode_literals import copy import json @@ -29,6 +28,9 @@ def get_pricing_rules(args, doc=None): pricing_rules = [] values = {} + if not frappe.db.exists('Pricing Rule', {'disable': 0, args.transaction_type: 1}): + return + for apply_on in ['Item Code', 'Item Group', 'Brand']: pricing_rules.extend(_get_pricing_rules(apply_on, args, values)) if pricing_rules and not apply_multiple_pricing_rules(pricing_rules): @@ -262,6 +264,11 @@ def filter_pricing_rules(args, pricing_rules, doc=None): else: p.variant_of = None + if len(pricing_rules) > 1: + filtered_rules = list(filter(lambda x: x.currency==args.get('currency'), pricing_rules)) + if filtered_rules: + pricing_rules = filtered_rules + # find pricing rule with highest priority if pricing_rules: max_priority = max(cint(p.priority) for p in pricing_rules) @@ -398,7 +405,9 @@ def get_qty_and_rate_for_other_item(doc, pr_doc, pricing_rules): pricing_rules[0].apply_rule_on_other_items = items return pricing_rules -def get_qty_amount_data_for_cumulative(pr_doc, doc, items=[]): +def get_qty_amount_data_for_cumulative(pr_doc, doc, items=None): + if items is None: + items = [] sum_qty, sum_amt = [0, 0] doctype = doc.get('parenttype') or doc.doctype diff --git a/erpnext/accounts/doctype/pricing_rule_brand/pricing_rule_brand.py b/erpnext/accounts/doctype/pricing_rule_brand/pricing_rule_brand.py index 5e10b8411a4..fdd5be0f6c3 100644 --- a/erpnext/accounts/doctype/pricing_rule_brand/pricing_rule_brand.py +++ b/erpnext/accounts/doctype/pricing_rule_brand/pricing_rule_brand.py @@ -1,8 +1,6 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2019, Frappe Technologies Pvt. Ltd. and contributors # For license information, please see license.txt -from __future__ import unicode_literals from frappe.model.document import Document diff --git a/erpnext/accounts/doctype/pricing_rule_detail/pricing_rule_detail.py b/erpnext/accounts/doctype/pricing_rule_detail/pricing_rule_detail.py index a90ecbb6f7f..f48b5695089 100644 --- a/erpnext/accounts/doctype/pricing_rule_detail/pricing_rule_detail.py +++ b/erpnext/accounts/doctype/pricing_rule_detail/pricing_rule_detail.py @@ -1,8 +1,6 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2019, Frappe Technologies Pvt. Ltd. and contributors # For license information, please see license.txt -from __future__ import unicode_literals from frappe.model.document import Document diff --git a/erpnext/accounts/doctype/pricing_rule_item_code/pricing_rule_item_code.py b/erpnext/accounts/doctype/pricing_rule_item_code/pricing_rule_item_code.py index 4746b39e175..f8a2c0e648c 100644 --- a/erpnext/accounts/doctype/pricing_rule_item_code/pricing_rule_item_code.py +++ b/erpnext/accounts/doctype/pricing_rule_item_code/pricing_rule_item_code.py @@ -1,8 +1,6 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2019, Frappe Technologies Pvt. Ltd. and contributors # For license information, please see license.txt -from __future__ import unicode_literals from frappe.model.document import Document diff --git a/erpnext/accounts/doctype/pricing_rule_item_group/pricing_rule_item_group.py b/erpnext/accounts/doctype/pricing_rule_item_group/pricing_rule_item_group.py index ff1ba75a60f..940350af902 100644 --- a/erpnext/accounts/doctype/pricing_rule_item_group/pricing_rule_item_group.py +++ b/erpnext/accounts/doctype/pricing_rule_item_group/pricing_rule_item_group.py @@ -1,8 +1,6 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2019, Frappe Technologies Pvt. Ltd. and contributors # For license information, please see license.txt -from __future__ import unicode_literals from frappe.model.document import Document diff --git a/erpnext/accounts/doctype/process_deferred_accounting/process_deferred_accounting.py b/erpnext/accounts/doctype/process_deferred_accounting/process_deferred_accounting.py index 72b7b23e149..d544f976d2a 100644 --- a/erpnext/accounts/doctype/process_deferred_accounting/process_deferred_accounting.py +++ b/erpnext/accounts/doctype/process_deferred_accounting/process_deferred_accounting.py @@ -1,8 +1,6 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2019, Frappe Technologies Pvt. Ltd. and contributors # For license information, please see license.txt -from __future__ import unicode_literals import frappe from frappe import _ diff --git a/erpnext/accounts/doctype/process_deferred_accounting/test_process_deferred_accounting.py b/erpnext/accounts/doctype/process_deferred_accounting/test_process_deferred_accounting.py index 69e2caa8e82..757d0fa3d01 100644 --- a/erpnext/accounts/doctype/process_deferred_accounting/test_process_deferred_accounting.py +++ b/erpnext/accounts/doctype/process_deferred_accounting/test_process_deferred_accounting.py @@ -1,7 +1,5 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2019, Frappe Technologies Pvt. Ltd. and Contributors # See license.txt -from __future__ import unicode_literals import unittest diff --git a/erpnext/accounts/doctype/process_statement_of_accounts/process_statement_of_accounts.json b/erpnext/accounts/doctype/process_statement_of_accounts/process_statement_of_accounts.json index 295a3b86a9e..a26267ba5e8 100644 --- a/erpnext/accounts/doctype/process_statement_of_accounts/process_statement_of_accounts.json +++ b/erpnext/accounts/doctype/process_statement_of_accounts/process_statement_of_accounts.json @@ -219,6 +219,7 @@ }, { "default": "1", + "description": "A customer must have primary contact email.", "fieldname": "primary_mandatory", "fieldtype": "Check", "label": "Send To Primary Contact" @@ -286,10 +287,11 @@ } ], "links": [], - "modified": "2021-05-21 11:14:22.426672", + "modified": "2021-09-06 21:00:45.732505", "modified_by": "Administrator", "module": "Accounts", "name": "Process Statement Of Accounts", + "naming_rule": "Set by user", "owner": "Administrator", "permissions": [ { diff --git a/erpnext/accounts/doctype/process_statement_of_accounts/process_statement_of_accounts.py b/erpnext/accounts/doctype/process_statement_of_accounts/process_statement_of_accounts.py index 73f30385120..09aa72352e4 100644 --- a/erpnext/accounts/doctype/process_statement_of_accounts/process_statement_of_accounts.py +++ b/erpnext/accounts/doctype/process_statement_of_accounts/process_statement_of_accounts.py @@ -1,8 +1,6 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2020, Frappe Technologies Pvt. Ltd. and contributors # For license information, please see license.txt -from __future__ import unicode_literals import copy @@ -196,7 +194,10 @@ def fetch_customers(customer_collection, collection_name, primary_mandatory): primary_email = customer.get('email_id') or '' billing_email = get_customer_emails(customer.name, 1, billing_and_primary=False) - if billing_email == '' or (primary_email == '' and int(primary_mandatory)): + if int(primary_mandatory): + if (primary_email == ''): + continue + elif (billing_email == '') and (primary_email == ''): continue customer_list.append({ @@ -208,10 +209,29 @@ def fetch_customers(customer_collection, collection_name, primary_mandatory): @frappe.whitelist() def get_customer_emails(customer_name, primary_mandatory, billing_and_primary=True): + """ Returns first email from Contact Email table as a Billing email + when Is Billing Contact checked + and Primary email- email with Is Primary checked """ + billing_email = frappe.db.sql(""" - SELECT c.email_id FROM `tabContact` AS c JOIN `tabDynamic Link` AS l ON c.name=l.parent - WHERE l.link_doctype='Customer' and l.link_name=%s and c.is_billing_contact=1 - order by c.creation desc""", customer_name) + SELECT + email.email_id + FROM + `tabContact Email` AS email + JOIN + `tabDynamic Link` AS link + ON + email.parent=link.parent + JOIN + `tabContact` AS contact + ON + contact.name=link.parent + WHERE + link.link_doctype='Customer' + and link.link_name=%s + and contact.is_billing_contact=1 + ORDER BY + contact.creation desc""", customer_name) if len(billing_email) == 0 or (billing_email[0][0] is None): if billing_and_primary: diff --git a/erpnext/accounts/doctype/process_statement_of_accounts/test_process_statement_of_accounts.py b/erpnext/accounts/doctype/process_statement_of_accounts/test_process_statement_of_accounts.py index 7ddcd105af9..c281040aaf2 100644 --- a/erpnext/accounts/doctype/process_statement_of_accounts/test_process_statement_of_accounts.py +++ b/erpnext/accounts/doctype/process_statement_of_accounts/test_process_statement_of_accounts.py @@ -1,7 +1,5 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2020, Frappe Technologies Pvt. Ltd. and Contributors # See license.txt -from __future__ import unicode_literals # import frappe import unittest diff --git a/erpnext/accounts/doctype/process_statement_of_accounts_customer/process_statement_of_accounts_customer.py b/erpnext/accounts/doctype/process_statement_of_accounts_customer/process_statement_of_accounts_customer.py index fe940094071..94fcb78e310 100644 --- a/erpnext/accounts/doctype/process_statement_of_accounts_customer/process_statement_of_accounts_customer.py +++ b/erpnext/accounts/doctype/process_statement_of_accounts_customer/process_statement_of_accounts_customer.py @@ -1,8 +1,6 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2020, Frappe Technologies Pvt. Ltd. and contributors # For license information, please see license.txt -from __future__ import unicode_literals # import frappe from frappe.model.document import Document diff --git a/erpnext/accounts/doctype/promotional_scheme/promotional_scheme.py b/erpnext/accounts/doctype/promotional_scheme/promotional_scheme.py index d09f7dc2da2..5fbe93ee68d 100644 --- a/erpnext/accounts/doctype/promotional_scheme/promotional_scheme.py +++ b/erpnext/accounts/doctype/promotional_scheme/promotional_scheme.py @@ -1,8 +1,6 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2019, Frappe Technologies Pvt. Ltd. and contributors # For license information, please see license.txt -from __future__ import unicode_literals import frappe from frappe import _ @@ -22,6 +20,9 @@ price_discount_fields = ['rate_or_discount', 'apply_discount_on', 'apply_discoun product_discount_fields = ['free_item', 'free_qty', 'free_item_uom', 'free_item_rate', 'same_item', 'is_recursive', 'apply_multiple_pricing_rules'] +class TransactionExists(frappe.ValidationError): + pass + class PromotionalScheme(Document): def validate(self): if not self.selling and not self.buying: @@ -30,6 +31,40 @@ class PromotionalScheme(Document): or self.product_discount_slabs): frappe.throw(_("Price or product discount slabs are required")) + self.validate_applicable_for() + self.validate_pricing_rules() + + def validate_applicable_for(self): + if self.applicable_for: + applicable_for = frappe.scrub(self.applicable_for) + + if not self.get(applicable_for): + msg = (f'The field {frappe.bold(self.applicable_for)} is required') + frappe.throw(_(msg)) + + def validate_pricing_rules(self): + if self.is_new(): + return + + transaction_exists = False + docnames = [] + + # If user has changed applicable for + if self._doc_before_save.applicable_for == self.applicable_for: + return + + docnames = frappe.get_all('Pricing Rule', + filters= {'promotional_scheme': self.name}) + + for docname in docnames: + if frappe.db.exists('Pricing Rule Detail', + {'pricing_rule': docname.name, 'docstatus': ('<', 2)}): + raise_for_transaction_exists(self.name) + + if docnames and not transaction_exists: + for docname in docnames: + frappe.delete_doc('Pricing Rule', docname.name) + def on_update(self): pricing_rules = frappe.get_all( 'Pricing Rule', @@ -69,7 +104,16 @@ class PromotionalScheme(Document): {'promotional_scheme': self.name}): frappe.delete_doc('Pricing Rule', rule.name) -def get_pricing_rules(doc, rules = {}): +def raise_for_transaction_exists(name): + msg = (f"""You can't change the {frappe.bold(_('Applicable For'))} + because transactions are present against the Promotional Scheme {frappe.bold(name)}. """) + msg += 'Kindly disable this Promotional Scheme and create new for new Applicable For.' + + frappe.throw(_(msg), TransactionExists) + +def get_pricing_rules(doc, rules=None): + if rules is None: + rules = {} new_doc = [] for child_doc, fields in {'price_discount_slabs': price_discount_fields, 'product_discount_slabs': product_discount_fields}.items(): @@ -78,49 +122,65 @@ def get_pricing_rules(doc, rules = {}): return new_doc -def _get_pricing_rules(doc, child_doc, discount_fields, rules = {}): +def _get_pricing_rules(doc, child_doc, discount_fields, rules=None): + if rules is None: + rules = {} new_doc = [] args = get_args_for_pricing_rule(doc) applicable_for = frappe.scrub(doc.get('applicable_for')) + for idx, d in enumerate(doc.get(child_doc)): if d.name in rules: - for applicable_for_value in args.get(applicable_for): - temp_args = args.copy() - docname = frappe.get_all( - 'Pricing Rule', - fields = ["promotional_scheme_id", "name", applicable_for], - filters = { - 'promotional_scheme_id': d.name, - applicable_for: applicable_for_value - } - ) - - if docname: - pr = frappe.get_doc('Pricing Rule', docname[0].get('name')) - temp_args[applicable_for] = applicable_for_value - pr = set_args(temp_args, pr, doc, child_doc, discount_fields, d) - else: - pr = frappe.new_doc("Pricing Rule") - pr.title = doc.name - temp_args[applicable_for] = applicable_for_value - pr = set_args(temp_args, pr, doc, child_doc, discount_fields, d) - + if not args.get(applicable_for): + docname = get_pricing_rule_docname(d) + pr = prepare_pricing_rule(args, doc, child_doc, discount_fields, d, docname) new_doc.append(pr) + else: + for applicable_for_value in args.get(applicable_for): + docname = get_pricing_rule_docname(d, applicable_for, applicable_for_value) + pr = prepare_pricing_rule(args, doc, child_doc, discount_fields, + d, docname, applicable_for, applicable_for_value) + new_doc.append(pr) - else: + elif args.get(applicable_for): applicable_for_values = args.get(applicable_for) or [] for applicable_for_value in applicable_for_values: - pr = frappe.new_doc("Pricing Rule") - pr.title = doc.name - temp_args = args.copy() - temp_args[applicable_for] = applicable_for_value - pr = set_args(temp_args, pr, doc, child_doc, discount_fields, d) + pr = prepare_pricing_rule(args, doc, child_doc, discount_fields, + d, applicable_for=applicable_for, value= applicable_for_value) + new_doc.append(pr) + else: + pr = prepare_pricing_rule(args, doc, child_doc, discount_fields, d) + new_doc.append(pr) return new_doc +def get_pricing_rule_docname(row: dict, applicable_for: str = None, applicable_for_value: str = None) -> str: + fields = ['promotional_scheme_id', 'name'] + filters = { + 'promotional_scheme_id': row.name + } + if applicable_for: + fields.append(applicable_for) + filters[applicable_for] = applicable_for_value + docname = frappe.get_all('Pricing Rule', fields = fields, filters = filters) + return docname[0].name if docname else '' + +def prepare_pricing_rule(args, doc, child_doc, discount_fields, d, docname=None, applicable_for=None, value=None): + if docname: + pr = frappe.get_doc("Pricing Rule", docname) + else: + pr = frappe.new_doc("Pricing Rule") + + pr.title = doc.name + temp_args = args.copy() + + if value: + temp_args[applicable_for] = value + + return set_args(temp_args, pr, doc, child_doc, discount_fields, d) def set_args(args, pr, doc, child_doc, discount_fields, child_doc_fields): pr.update(args) @@ -143,6 +203,7 @@ def set_args(args, pr, doc, child_doc, discount_fields, child_doc_fields): apply_on: d.get(apply_on), 'uom': d.uom }) + return pr def get_args_for_pricing_rule(doc): diff --git a/erpnext/accounts/doctype/promotional_scheme/test_promotional_scheme.py b/erpnext/accounts/doctype/promotional_scheme/test_promotional_scheme.py index 190b734cc17..49192a45f87 100644 --- a/erpnext/accounts/doctype/promotional_scheme/test_promotional_scheme.py +++ b/erpnext/accounts/doctype/promotional_scheme/test_promotional_scheme.py @@ -1,16 +1,21 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2019, Frappe Technologies Pvt. Ltd. and Contributors # See license.txt -from __future__ import unicode_literals import unittest import frappe +from erpnext.accounts.doctype.promotional_scheme.promotional_scheme import TransactionExists +from erpnext.selling.doctype.sales_order.test_sales_order import make_sales_order + class TestPromotionalScheme(unittest.TestCase): + def setUp(self): + if frappe.db.exists('Promotional Scheme', '_Test Scheme'): + frappe.delete_doc('Promotional Scheme', '_Test Scheme') + def test_promotional_scheme(self): - ps = make_promotional_scheme() + ps = make_promotional_scheme(applicable_for='Customer', customer='_Test Customer') price_rules = frappe.get_all('Pricing Rule', fields = ["promotional_scheme_id", "name", "creation"], filters = {'promotional_scheme': ps.name}) self.assertTrue(len(price_rules),1) @@ -41,22 +46,62 @@ class TestPromotionalScheme(unittest.TestCase): filters = {'promotional_scheme': ps.name}) self.assertEqual(price_rules, []) -def make_promotional_scheme(): + def test_promotional_scheme_without_applicable_for(self): + ps = make_promotional_scheme() + price_rules = frappe.get_all('Pricing Rule', filters = {'promotional_scheme': ps.name}) + + self.assertTrue(len(price_rules), 1) + frappe.delete_doc('Promotional Scheme', ps.name) + + price_rules = frappe.get_all('Pricing Rule', filters = {'promotional_scheme': ps.name}) + self.assertEqual(price_rules, []) + + def test_change_applicable_for_in_promotional_scheme(self): + ps = make_promotional_scheme() + price_rules = frappe.get_all('Pricing Rule', filters = {'promotional_scheme': ps.name}) + self.assertTrue(len(price_rules), 1) + + so = make_sales_order(qty=5, currency='USD', do_not_save=True) + so.set_missing_values() + so.save() + self.assertEqual(price_rules[0].name, so.pricing_rules[0].pricing_rule) + + ps.applicable_for = 'Customer' + ps.append('customer', { + 'customer': '_Test Customer' + }) + + self.assertRaises(TransactionExists, ps.save) + + frappe.delete_doc('Sales Order', so.name) + frappe.delete_doc('Promotional Scheme', ps.name) + price_rules = frappe.get_all('Pricing Rule', filters = {'promotional_scheme': ps.name}) + self.assertEqual(price_rules, []) + +def make_promotional_scheme(**args): + args = frappe._dict(args) + ps = frappe.new_doc('Promotional Scheme') ps.name = '_Test Scheme' ps.append('items',{ 'item_code': '_Test Item' }) + ps.selling = 1 ps.append('price_discount_slabs',{ 'min_qty': 4, + 'validate_applied_rule': 0, 'discount_percentage': 20, 'rule_description': 'Test' }) - ps.applicable_for = 'Customer' - ps.append('customer',{ - 'customer': "_Test Customer" - }) + + ps.company = '_Test Company' + if args.applicable_for: + ps.applicable_for = args.applicable_for + ps.append(frappe.scrub(args.applicable_for), { + frappe.scrub(args.applicable_for): args.get(frappe.scrub(args.applicable_for)) + }) + ps.save() return ps diff --git a/erpnext/accounts/doctype/promotional_scheme_price_discount/promotional_scheme_price_discount.json b/erpnext/accounts/doctype/promotional_scheme_price_discount/promotional_scheme_price_discount.json index a70d5c9d430..aa3696d216d 100644 --- a/erpnext/accounts/doctype/promotional_scheme_price_discount/promotional_scheme_price_discount.json +++ b/erpnext/accounts/doctype/promotional_scheme_price_discount/promotional_scheme_price_discount.json @@ -136,7 +136,7 @@ "label": "Threshold for Suggestion" }, { - "default": "1", + "default": "0", "fieldname": "validate_applied_rule", "fieldtype": "Check", "label": "Validate Applied Rule" @@ -169,7 +169,7 @@ "index_web_pages_for_search": 1, "istable": 1, "links": [], - "modified": "2021-08-19 15:49:29.598727", + "modified": "2021-11-16 00:25:33.843996", "modified_by": "Administrator", "module": "Accounts", "name": "Promotional Scheme Price Discount", diff --git a/erpnext/accounts/doctype/promotional_scheme_price_discount/promotional_scheme_price_discount.py b/erpnext/accounts/doctype/promotional_scheme_price_discount/promotional_scheme_price_discount.py index ab8efc33141..a0e220004ee 100644 --- a/erpnext/accounts/doctype/promotional_scheme_price_discount/promotional_scheme_price_discount.py +++ b/erpnext/accounts/doctype/promotional_scheme_price_discount/promotional_scheme_price_discount.py @@ -1,8 +1,6 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2019, Frappe Technologies Pvt. Ltd. and contributors # For license information, please see license.txt -from __future__ import unicode_literals from frappe.model.document import Document diff --git a/erpnext/accounts/doctype/promotional_scheme_product_discount/promotional_scheme_product_discount.py b/erpnext/accounts/doctype/promotional_scheme_product_discount/promotional_scheme_product_discount.py index 85019b4e455..c9f6f863467 100644 --- a/erpnext/accounts/doctype/promotional_scheme_product_discount/promotional_scheme_product_discount.py +++ b/erpnext/accounts/doctype/promotional_scheme_product_discount/promotional_scheme_product_discount.py @@ -1,8 +1,6 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2019, Frappe Technologies Pvt. Ltd. and contributors # For license information, please see license.txt -from __future__ import unicode_literals from frappe.model.document import Document diff --git a/erpnext/accounts/doctype/psoa_cost_center/psoa_cost_center.py b/erpnext/accounts/doctype/psoa_cost_center/psoa_cost_center.py index cb5aaa9c5e0..877998a187c 100644 --- a/erpnext/accounts/doctype/psoa_cost_center/psoa_cost_center.py +++ b/erpnext/accounts/doctype/psoa_cost_center/psoa_cost_center.py @@ -1,8 +1,6 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2020, Frappe Technologies Pvt. Ltd. and contributors # For license information, please see license.txt -from __future__ import unicode_literals # import frappe from frappe.model.document import Document diff --git a/erpnext/accounts/doctype/psoa_project/psoa_project.py b/erpnext/accounts/doctype/psoa_project/psoa_project.py index 1cd995179d5..de22bb73047 100644 --- a/erpnext/accounts/doctype/psoa_project/psoa_project.py +++ b/erpnext/accounts/doctype/psoa_project/psoa_project.py @@ -1,8 +1,6 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2020, Frappe Technologies Pvt. Ltd. and contributors # For license information, please see license.txt -from __future__ import unicode_literals # import frappe from frappe.model.document import Document diff --git a/erpnext/accounts/doctype/purchase_invoice/__init__.py b/erpnext/accounts/doctype/purchase_invoice/__init__.py index baffc488252..e69de29bb2d 100644 --- a/erpnext/accounts/doctype/purchase_invoice/__init__.py +++ b/erpnext/accounts/doctype/purchase_invoice/__init__.py @@ -1 +0,0 @@ -from __future__ import unicode_literals diff --git a/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.js b/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.js index 6c74d2b438f..1a398aba2ec 100644 --- a/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.js +++ b/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.js @@ -590,5 +590,20 @@ frappe.ui.form.on("Purchase Invoice", { company: function(frm) { erpnext.accounts.dimensions.update_dimension(frm, frm.doctype); + + if (frm.doc.company) { + frappe.call({ + method: + "erpnext.accounts.party.get_party_account", + args: { + party_type: 'Supplier', + party: frm.doc.supplier, + company: frm.doc.company + }, + callback: (response) => { + if (response) frm.set_value("credit_to", response.message); + }, + }); + } }, }) diff --git a/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.json b/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.json index 7822f747f64..03cbc4acbc4 100644 --- a/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.json +++ b/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.json @@ -149,16 +149,18 @@ "cb_17", "hold_comment", "more_info", + "status", + "inter_company_invoice_reference", + "represents_company", + "column_break_147", + "is_internal_supplier", + "accounting_details_section", "credit_to", "party_account_currency", "is_opening", "against_expense_account", "column_break_63", "unrealized_profit_loss_account", - "status", - "inter_company_invoice_reference", - "is_internal_supplier", - "represents_company", "remarks", "subscription_section", "from_date", @@ -177,9 +179,7 @@ "hidden": 1, "label": "Title", "no_copy": 1, - "print_hide": 1, - "show_days": 1, - "show_seconds": 1 + "print_hide": 1 }, { "fieldname": "naming_series", @@ -191,9 +191,7 @@ "options": "ACC-PINV-.YYYY.-\nACC-PINV-RET-.YYYY.-", "print_hide": 1, "reqd": 1, - "set_only_once": 1, - "show_days": 1, - "show_seconds": 1 + "set_only_once": 1 }, { "fieldname": "supplier", @@ -205,9 +203,7 @@ "options": "Supplier", "print_hide": 1, "reqd": 1, - "search_index": 1, - "show_days": 1, - "show_seconds": 1 + "search_index": 1 }, { "bold": 1, @@ -219,9 +215,7 @@ "label": "Supplier Name", "oldfieldname": "supplier_name", "oldfieldtype": "Data", - "read_only": 1, - "show_days": 1, - "show_seconds": 1 + "read_only": 1 }, { "fetch_from": "supplier.tax_id", @@ -229,27 +223,21 @@ "fieldtype": "Read Only", "label": "Tax Id", "print_hide": 1, - "read_only": 1, - "show_days": 1, - "show_seconds": 1 + "read_only": 1 }, { "fieldname": "due_date", "fieldtype": "Date", "label": "Due Date", "oldfieldname": "due_date", - "oldfieldtype": "Date", - "show_days": 1, - "show_seconds": 1 + "oldfieldtype": "Date" }, { "default": "0", "fieldname": "is_paid", "fieldtype": "Check", "label": "Is Paid", - "print_hide": 1, - "show_days": 1, - "show_seconds": 1 + "print_hide": 1 }, { "default": "0", @@ -257,25 +245,19 @@ "fieldtype": "Check", "label": "Is Return (Debit Note)", "no_copy": 1, - "print_hide": 1, - "show_days": 1, - "show_seconds": 1 + "print_hide": 1 }, { "default": "0", "fieldname": "apply_tds", "fieldtype": "Check", "label": "Apply Tax Withholding Amount", - "print_hide": 1, - "show_days": 1, - "show_seconds": 1 + "print_hide": 1 }, { "fieldname": "column_break1", "fieldtype": "Column Break", "oldfieldtype": "Column Break", - "show_days": 1, - "show_seconds": 1, "width": "50%" }, { @@ -285,17 +267,13 @@ "label": "Company", "options": "Company", "print_hide": 1, - "remember_last_selected_value": 1, - "show_days": 1, - "show_seconds": 1 + "remember_last_selected_value": 1 }, { "fieldname": "cost_center", "fieldtype": "Link", "label": "Cost Center", - "options": "Cost Center", - "show_days": 1, - "show_seconds": 1 + "options": "Cost Center" }, { "default": "Today", @@ -307,9 +285,7 @@ "oldfieldtype": "Date", "print_hide": 1, "reqd": 1, - "search_index": 1, - "show_days": 1, - "show_seconds": 1 + "search_index": 1 }, { "fieldname": "posting_time", @@ -318,8 +294,6 @@ "no_copy": 1, "print_hide": 1, "print_width": "100px", - "show_days": 1, - "show_seconds": 1, "width": "100px" }, { @@ -328,9 +302,7 @@ "fieldname": "set_posting_time", "fieldtype": "Check", "label": "Edit Posting Date and Time", - "print_hide": 1, - "show_days": 1, - "show_seconds": 1 + "print_hide": 1 }, { "fieldname": "amended_from", @@ -342,58 +314,44 @@ "oldfieldtype": "Link", "options": "Purchase Invoice", "print_hide": 1, - "read_only": 1, - "show_days": 1, - "show_seconds": 1 + "read_only": 1 }, { "collapsible": 1, "collapsible_depends_on": "eval:doc.on_hold", "fieldname": "sb_14", "fieldtype": "Section Break", - "label": "Hold Invoice", - "show_days": 1, - "show_seconds": 1 + "label": "Hold Invoice" }, { "default": "0", "fieldname": "on_hold", "fieldtype": "Check", - "label": "Hold Invoice", - "show_days": 1, - "show_seconds": 1 + "label": "Hold Invoice" }, { "depends_on": "eval:doc.on_hold", "description": "Once set, this invoice will be on hold till the set date", "fieldname": "release_date", "fieldtype": "Date", - "label": "Release Date", - "show_days": 1, - "show_seconds": 1 + "label": "Release Date" }, { "fieldname": "cb_17", - "fieldtype": "Column Break", - "show_days": 1, - "show_seconds": 1 + "fieldtype": "Column Break" }, { "depends_on": "eval:doc.on_hold", "fieldname": "hold_comment", "fieldtype": "Small Text", - "label": "Reason For Putting On Hold", - "show_days": 1, - "show_seconds": 1 + "label": "Reason For Putting On Hold" }, { "collapsible": 1, "collapsible_depends_on": "bill_no", "fieldname": "supplier_invoice_details", "fieldtype": "Section Break", - "label": "Supplier Invoice Details", - "show_days": 1, - "show_seconds": 1 + "label": "Supplier Invoice Details" }, { "fieldname": "bill_no", @@ -401,15 +359,11 @@ "label": "Supplier Invoice No", "oldfieldname": "bill_no", "oldfieldtype": "Data", - "print_hide": 1, - "show_days": 1, - "show_seconds": 1 + "print_hide": 1 }, { "fieldname": "column_break_15", - "fieldtype": "Column Break", - "show_days": 1, - "show_seconds": 1 + "fieldtype": "Column Break" }, { "fieldname": "bill_date", @@ -418,17 +372,13 @@ "no_copy": 1, "oldfieldname": "bill_date", "oldfieldtype": "Date", - "print_hide": 1, - "show_days": 1, - "show_seconds": 1 + "print_hide": 1 }, { "depends_on": "return_against", "fieldname": "returns", "fieldtype": "Section Break", - "label": "Returns", - "show_days": 1, - "show_seconds": 1 + "label": "Returns" }, { "depends_on": "return_against", @@ -438,34 +388,26 @@ "no_copy": 1, "options": "Purchase Invoice", "print_hide": 1, - "read_only": 1, - "show_days": 1, - "show_seconds": 1 + "read_only": 1 }, { "collapsible": 1, "fieldname": "section_addresses", "fieldtype": "Section Break", - "label": "Address and Contact", - "show_days": 1, - "show_seconds": 1 + "label": "Address and Contact" }, { "fieldname": "supplier_address", "fieldtype": "Link", "label": "Select Supplier Address", "options": "Address", - "print_hide": 1, - "show_days": 1, - "show_seconds": 1 + "print_hide": 1 }, { "fieldname": "address_display", "fieldtype": "Small Text", "label": "Address", - "read_only": 1, - "show_days": 1, - "show_seconds": 1 + "read_only": 1 }, { "fieldname": "contact_person", @@ -473,67 +415,51 @@ "in_global_search": 1, "label": "Contact Person", "options": "Contact", - "print_hide": 1, - "show_days": 1, - "show_seconds": 1 + "print_hide": 1 }, { "fieldname": "contact_display", "fieldtype": "Small Text", "label": "Contact", - "read_only": 1, - "show_days": 1, - "show_seconds": 1 + "read_only": 1 }, { "fieldname": "contact_mobile", "fieldtype": "Small Text", "label": "Mobile No", - "read_only": 1, - "show_days": 1, - "show_seconds": 1 + "read_only": 1 }, { "fieldname": "contact_email", "fieldtype": "Small Text", "label": "Contact Email", "print_hide": 1, - "read_only": 1, - "show_days": 1, - "show_seconds": 1 + "read_only": 1 }, { "fieldname": "col_break_address", - "fieldtype": "Column Break", - "show_days": 1, - "show_seconds": 1 + "fieldtype": "Column Break" }, { "fieldname": "shipping_address", "fieldtype": "Link", "label": "Select Shipping Address", "options": "Address", - "print_hide": 1, - "show_days": 1, - "show_seconds": 1 + "print_hide": 1 }, { "fieldname": "shipping_address_display", "fieldtype": "Small Text", "label": "Shipping Address", "print_hide": 1, - "read_only": 1, - "show_days": 1, - "show_seconds": 1 + "read_only": 1 }, { "collapsible": 1, "fieldname": "currency_and_price_list", "fieldtype": "Section Break", "label": "Currency and Price List", - "options": "fa fa-tag", - "show_days": 1, - "show_seconds": 1 + "options": "fa fa-tag" }, { "fieldname": "currency", @@ -542,9 +468,7 @@ "oldfieldname": "currency", "oldfieldtype": "Select", "options": "Currency", - "print_hide": 1, - "show_days": 1, - "show_seconds": 1 + "print_hide": 1 }, { "fieldname": "conversion_rate", @@ -553,24 +477,18 @@ "oldfieldname": "conversion_rate", "oldfieldtype": "Currency", "precision": "9", - "print_hide": 1, - "show_days": 1, - "show_seconds": 1 + "print_hide": 1 }, { "fieldname": "column_break2", - "fieldtype": "Column Break", - "show_days": 1, - "show_seconds": 1 + "fieldtype": "Column Break" }, { "fieldname": "buying_price_list", "fieldtype": "Link", "label": "Price List", "options": "Price List", - "print_hide": 1, - "show_days": 1, - "show_seconds": 1 + "print_hide": 1 }, { "fieldname": "price_list_currency", @@ -578,18 +496,14 @@ "label": "Price List Currency", "options": "Currency", "print_hide": 1, - "read_only": 1, - "show_days": 1, - "show_seconds": 1 + "read_only": 1 }, { "fieldname": "plc_conversion_rate", "fieldtype": "Float", "label": "Price List Exchange Rate", "precision": "9", - "print_hide": 1, - "show_days": 1, - "show_seconds": 1 + "print_hide": 1 }, { "default": "0", @@ -598,15 +512,11 @@ "label": "Ignore Pricing Rule", "no_copy": 1, "permlevel": 1, - "print_hide": 1, - "show_days": 1, - "show_seconds": 1 + "print_hide": 1 }, { "fieldname": "sec_warehouse", - "fieldtype": "Section Break", - "show_days": 1, - "show_seconds": 1 + "fieldtype": "Section Break" }, { "depends_on": "update_stock", @@ -615,9 +525,7 @@ "fieldtype": "Link", "label": "Set Accepted Warehouse", "options": "Warehouse", - "print_hide": 1, - "show_days": 1, - "show_seconds": 1 + "print_hide": 1 }, { "depends_on": "update_stock", @@ -627,15 +535,11 @@ "label": "Rejected Warehouse", "no_copy": 1, "options": "Warehouse", - "print_hide": 1, - "show_days": 1, - "show_seconds": 1 + "print_hide": 1 }, { "fieldname": "col_break_warehouse", - "fieldtype": "Column Break", - "show_days": 1, - "show_seconds": 1 + "fieldtype": "Column Break" }, { "default": "No", @@ -643,26 +547,20 @@ "fieldtype": "Select", "label": "Raw Materials Supplied", "options": "No\nYes", - "print_hide": 1, - "show_days": 1, - "show_seconds": 1 + "print_hide": 1 }, { "fieldname": "items_section", "fieldtype": "Section Break", "oldfieldtype": "Section Break", - "options": "fa fa-shopping-cart", - "show_days": 1, - "show_seconds": 1 + "options": "fa fa-shopping-cart" }, { "default": "0", "fieldname": "update_stock", "fieldtype": "Check", "label": "Update Stock", - "print_hide": 1, - "show_days": 1, - "show_seconds": 1 + "print_hide": 1 }, { "fieldname": "scan_barcode", @@ -678,33 +576,25 @@ "oldfieldname": "entries", "oldfieldtype": "Table", "options": "Purchase Invoice Item", - "reqd": 1, - "show_days": 1, - "show_seconds": 1 + "reqd": 1 }, { "fieldname": "pricing_rule_details", "fieldtype": "Section Break", - "label": "Pricing Rules", - "show_days": 1, - "show_seconds": 1 + "label": "Pricing Rules" }, { "fieldname": "pricing_rules", "fieldtype": "Table", "label": "Pricing Rule Detail", "options": "Pricing Rule Detail", - "read_only": 1, - "show_days": 1, - "show_seconds": 1 + "read_only": 1 }, { "collapsible_depends_on": "supplied_items", "fieldname": "raw_materials_supplied", "fieldtype": "Section Break", - "label": "Raw Materials Supplied", - "show_days": 1, - "show_seconds": 1 + "label": "Raw Materials Supplied" }, { "depends_on": "update_stock", @@ -712,23 +602,17 @@ "fieldtype": "Table", "label": "Supplied Items", "no_copy": 1, - "options": "Purchase Receipt Item Supplied", - "show_days": 1, - "show_seconds": 1 + "options": "Purchase Receipt Item Supplied" }, { "fieldname": "section_break_26", - "fieldtype": "Section Break", - "show_days": 1, - "show_seconds": 1 + "fieldtype": "Section Break" }, { "fieldname": "total_qty", "fieldtype": "Float", "label": "Total Quantity", - "read_only": 1, - "show_days": 1, - "show_seconds": 1 + "read_only": 1 }, { "fieldname": "base_total", @@ -736,9 +620,7 @@ "label": "Total (Company Currency)", "options": "Company:company:default_currency", "print_hide": 1, - "read_only": 1, - "show_days": 1, - "show_seconds": 1 + "read_only": 1 }, { "fieldname": "base_net_total", @@ -748,24 +630,18 @@ "oldfieldtype": "Currency", "options": "Company:company:default_currency", "print_hide": 1, - "read_only": 1, - "show_days": 1, - "show_seconds": 1 + "read_only": 1 }, { "fieldname": "column_break_28", - "fieldtype": "Column Break", - "show_days": 1, - "show_seconds": 1 + "fieldtype": "Column Break" }, { "fieldname": "total", "fieldtype": "Currency", "label": "Total", "options": "currency", - "read_only": 1, - "show_days": 1, - "show_seconds": 1 + "read_only": 1 }, { "fieldname": "net_total", @@ -775,56 +651,42 @@ "oldfieldtype": "Currency", "options": "currency", "print_hide": 1, - "read_only": 1, - "show_days": 1, - "show_seconds": 1 + "read_only": 1 }, { "fieldname": "total_net_weight", "fieldtype": "Float", "label": "Total Net Weight", "print_hide": 1, - "read_only": 1, - "show_days": 1, - "show_seconds": 1 + "read_only": 1 }, { "fieldname": "taxes_section", "fieldtype": "Section Break", "oldfieldtype": "Section Break", - "options": "fa fa-money", - "show_days": 1, - "show_seconds": 1 + "options": "fa fa-money" }, { "fieldname": "tax_category", "fieldtype": "Link", "label": "Tax Category", "options": "Tax Category", - "print_hide": 1, - "show_days": 1, - "show_seconds": 1 + "print_hide": 1 }, { "fieldname": "column_break_49", - "fieldtype": "Column Break", - "show_days": 1, - "show_seconds": 1 + "fieldtype": "Column Break" }, { "fieldname": "shipping_rule", "fieldtype": "Link", "label": "Shipping Rule", "options": "Shipping Rule", - "print_hide": 1, - "show_days": 1, - "show_seconds": 1 + "print_hide": 1 }, { "fieldname": "section_break_51", - "fieldtype": "Section Break", - "show_days": 1, - "show_seconds": 1 + "fieldtype": "Section Break" }, { "fieldname": "taxes_and_charges", @@ -833,9 +695,7 @@ "oldfieldname": "purchase_other_charges", "oldfieldtype": "Link", "options": "Purchase Taxes and Charges Template", - "print_hide": 1, - "show_days": 1, - "show_seconds": 1 + "print_hide": 1 }, { "fieldname": "taxes", @@ -843,17 +703,13 @@ "label": "Purchase Taxes and Charges", "oldfieldname": "purchase_tax_details", "oldfieldtype": "Table", - "options": "Purchase Taxes and Charges", - "show_days": 1, - "show_seconds": 1 + "options": "Purchase Taxes and Charges" }, { "collapsible": 1, "fieldname": "sec_tax_breakup", "fieldtype": "Section Break", - "label": "Tax Breakup", - "show_days": 1, - "show_seconds": 1 + "label": "Tax Breakup" }, { "fieldname": "other_charges_calculation", @@ -862,17 +718,13 @@ "no_copy": 1, "oldfieldtype": "HTML", "print_hide": 1, - "read_only": 1, - "show_days": 1, - "show_seconds": 1 + "read_only": 1 }, { "fieldname": "totals", "fieldtype": "Section Break", "oldfieldtype": "Section Break", - "options": "fa fa-money", - "show_days": 1, - "show_seconds": 1 + "options": "fa fa-money" }, { "fieldname": "base_taxes_and_charges_added", @@ -882,9 +734,7 @@ "oldfieldtype": "Currency", "options": "Company:company:default_currency", "print_hide": 1, - "read_only": 1, - "show_days": 1, - "show_seconds": 1 + "read_only": 1 }, { "fieldname": "base_taxes_and_charges_deducted", @@ -894,9 +744,7 @@ "oldfieldtype": "Currency", "options": "Company:company:default_currency", "print_hide": 1, - "read_only": 1, - "show_days": 1, - "show_seconds": 1 + "read_only": 1 }, { "fieldname": "base_total_taxes_and_charges", @@ -906,15 +754,11 @@ "oldfieldtype": "Currency", "options": "Company:company:default_currency", "print_hide": 1, - "read_only": 1, - "show_days": 1, - "show_seconds": 1 + "read_only": 1 }, { "fieldname": "column_break_40", - "fieldtype": "Column Break", - "show_days": 1, - "show_seconds": 1 + "fieldtype": "Column Break" }, { "fieldname": "taxes_and_charges_added", @@ -924,9 +768,7 @@ "oldfieldtype": "Currency", "options": "currency", "print_hide": 1, - "read_only": 1, - "show_days": 1, - "show_seconds": 1 + "read_only": 1 }, { "fieldname": "taxes_and_charges_deducted", @@ -936,9 +778,7 @@ "oldfieldtype": "Currency", "options": "currency", "print_hide": 1, - "read_only": 1, - "show_days": 1, - "show_seconds": 1 + "read_only": 1 }, { "fieldname": "total_taxes_and_charges", @@ -946,18 +786,14 @@ "label": "Total Taxes and Charges", "options": "currency", "print_hide": 1, - "read_only": 1, - "show_days": 1, - "show_seconds": 1 + "read_only": 1 }, { "collapsible": 1, "collapsible_depends_on": "discount_amount", "fieldname": "section_break_44", "fieldtype": "Section Break", - "label": "Additional Discount", - "show_days": 1, - "show_seconds": 1 + "label": "Additional Discount" }, { "default": "Grand Total", @@ -965,9 +801,7 @@ "fieldtype": "Select", "label": "Apply Additional Discount On", "options": "\nGrand Total\nNet Total", - "print_hide": 1, - "show_days": 1, - "show_seconds": 1 + "print_hide": 1 }, { "fieldname": "base_discount_amount", @@ -975,38 +809,28 @@ "label": "Additional Discount Amount (Company Currency)", "options": "Company:company:default_currency", "print_hide": 1, - "read_only": 1, - "show_days": 1, - "show_seconds": 1 + "read_only": 1 }, { "fieldname": "column_break_46", - "fieldtype": "Column Break", - "show_days": 1, - "show_seconds": 1 + "fieldtype": "Column Break" }, { "fieldname": "additional_discount_percentage", "fieldtype": "Float", "label": "Additional Discount Percentage", - "print_hide": 1, - "show_days": 1, - "show_seconds": 1 + "print_hide": 1 }, { "fieldname": "discount_amount", "fieldtype": "Currency", "label": "Additional Discount Amount", "options": "currency", - "print_hide": 1, - "show_days": 1, - "show_seconds": 1 + "print_hide": 1 }, { "fieldname": "section_break_49", - "fieldtype": "Section Break", - "show_days": 1, - "show_seconds": 1 + "fieldtype": "Section Break" }, { "fieldname": "base_grand_total", @@ -1016,9 +840,7 @@ "oldfieldtype": "Currency", "options": "Company:company:default_currency", "print_hide": 1, - "read_only": 1, - "show_days": 1, - "show_seconds": 1 + "read_only": 1 }, { "depends_on": "eval:!doc.disable_rounded_total", @@ -1028,9 +850,7 @@ "no_copy": 1, "options": "Company:company:default_currency", "print_hide": 1, - "read_only": 1, - "show_days": 1, - "show_seconds": 1 + "read_only": 1 }, { "depends_on": "eval:!doc.disable_rounded_total", @@ -1040,9 +860,7 @@ "no_copy": 1, "options": "Company:company:default_currency", "print_hide": 1, - "read_only": 1, - "show_days": 1, - "show_seconds": 1 + "read_only": 1 }, { "fieldname": "base_in_words", @@ -1052,17 +870,13 @@ "oldfieldname": "in_words", "oldfieldtype": "Data", "print_hide": 1, - "read_only": 1, - "show_days": 1, - "show_seconds": 1 + "read_only": 1 }, { "fieldname": "column_break8", "fieldtype": "Column Break", "oldfieldtype": "Column Break", "print_hide": 1, - "show_days": 1, - "show_seconds": 1, "width": "50%" }, { @@ -1073,9 +887,7 @@ "oldfieldname": "grand_total_import", "oldfieldtype": "Currency", "options": "currency", - "read_only": 1, - "show_days": 1, - "show_seconds": 1 + "read_only": 1 }, { "depends_on": "eval:!doc.disable_rounded_total", @@ -1085,9 +897,7 @@ "no_copy": 1, "options": "currency", "print_hide": 1, - "read_only": 1, - "show_days": 1, - "show_seconds": 1 + "read_only": 1 }, { "depends_on": "eval:!doc.disable_rounded_total", @@ -1097,9 +907,7 @@ "no_copy": 1, "options": "currency", "print_hide": 1, - "read_only": 1, - "show_days": 1, - "show_seconds": 1 + "read_only": 1 }, { "fieldname": "in_words", @@ -1109,9 +917,7 @@ "oldfieldname": "in_words_import", "oldfieldtype": "Data", "print_hide": 1, - "read_only": 1, - "show_days": 1, - "show_seconds": 1 + "read_only": 1 }, { "fieldname": "total_advance", @@ -1122,9 +928,7 @@ "oldfieldtype": "Currency", "options": "party_account_currency", "print_hide": 1, - "read_only": 1, - "show_days": 1, - "show_seconds": 1 + "read_only": 1 }, { "fieldname": "outstanding_amount", @@ -1135,18 +939,14 @@ "oldfieldtype": "Currency", "options": "party_account_currency", "print_hide": 1, - "read_only": 1, - "show_days": 1, - "show_seconds": 1 + "read_only": 1 }, { "default": "0", "depends_on": "grand_total", "fieldname": "disable_rounded_total", "fieldtype": "Check", - "label": "Disable Rounded Total", - "show_days": 1, - "show_seconds": 1 + "label": "Disable Rounded Total" }, { "collapsible": 1, @@ -1154,26 +954,20 @@ "depends_on": "eval:doc.is_paid===1||(doc.advances && doc.advances.length>0)", "fieldname": "payments_section", "fieldtype": "Section Break", - "label": "Payments", - "show_days": 1, - "show_seconds": 1 + "label": "Payments" }, { "fieldname": "mode_of_payment", "fieldtype": "Link", "label": "Mode of Payment", "options": "Mode of Payment", - "print_hide": 1, - "show_days": 1, - "show_seconds": 1 + "print_hide": 1 }, { "fieldname": "cash_bank_account", "fieldtype": "Link", "label": "Cash/Bank Account", - "options": "Account", - "show_days": 1, - "show_seconds": 1 + "options": "Account" }, { "fieldname": "clearance_date", @@ -1181,15 +975,11 @@ "label": "Clearance Date", "no_copy": 1, "print_hide": 1, - "read_only": 1, - "show_days": 1, - "show_seconds": 1 + "read_only": 1 }, { "fieldname": "col_br_payments", - "fieldtype": "Column Break", - "show_days": 1, - "show_seconds": 1 + "fieldtype": "Column Break" }, { "depends_on": "is_paid", @@ -1198,9 +988,7 @@ "label": "Paid Amount", "no_copy": 1, "options": "currency", - "print_hide": 1, - "show_days": 1, - "show_seconds": 1 + "print_hide": 1 }, { "fieldname": "base_paid_amount", @@ -1209,9 +997,7 @@ "no_copy": 1, "options": "Company:company:default_currency", "print_hide": 1, - "read_only": 1, - "show_days": 1, - "show_seconds": 1 + "read_only": 1 }, { "collapsible": 1, @@ -1219,9 +1005,7 @@ "depends_on": "grand_total", "fieldname": "write_off", "fieldtype": "Section Break", - "label": "Write Off", - "show_days": 1, - "show_seconds": 1 + "label": "Write Off" }, { "fieldname": "write_off_amount", @@ -1229,9 +1013,7 @@ "label": "Write Off Amount", "no_copy": 1, "options": "currency", - "print_hide": 1, - "show_days": 1, - "show_seconds": 1 + "print_hide": 1 }, { "fieldname": "base_write_off_amount", @@ -1240,15 +1022,11 @@ "no_copy": 1, "options": "Company:company:default_currency", "print_hide": 1, - "read_only": 1, - "show_days": 1, - "show_seconds": 1 + "read_only": 1 }, { "fieldname": "column_break_61", - "fieldtype": "Column Break", - "show_days": 1, - "show_seconds": 1 + "fieldtype": "Column Break" }, { "depends_on": "eval:flt(doc.write_off_amount)!=0", @@ -1256,9 +1034,7 @@ "fieldtype": "Link", "label": "Write Off Account", "options": "Account", - "print_hide": 1, - "show_days": 1, - "show_seconds": 1 + "print_hide": 1 }, { "depends_on": "eval:flt(doc.write_off_amount)!=0", @@ -1266,9 +1042,7 @@ "fieldtype": "Link", "label": "Write Off Cost Center", "options": "Cost Center", - "print_hide": 1, - "show_days": 1, - "show_seconds": 1 + "print_hide": 1 }, { "collapsible": 1, @@ -1278,17 +1052,13 @@ "label": "Advance Payments", "oldfieldtype": "Section Break", "options": "fa fa-money", - "print_hide": 1, - "show_days": 1, - "show_seconds": 1 + "print_hide": 1 }, { "default": "0", "fieldname": "allocate_advances_automatically", "fieldtype": "Check", - "label": "Set Advances and Allocate (FIFO)", - "show_days": 1, - "show_seconds": 1 + "label": "Set Advances and Allocate (FIFO)" }, { "depends_on": "eval:!doc.allocate_advances_automatically", @@ -1296,9 +1066,7 @@ "fieldtype": "Button", "label": "Get Advances Paid", "oldfieldtype": "Button", - "print_hide": 1, - "show_days": 1, - "show_seconds": 1 + "print_hide": 1 }, { "fieldname": "advances", @@ -1308,26 +1076,20 @@ "oldfieldname": "advance_allocation_details", "oldfieldtype": "Table", "options": "Purchase Invoice Advance", - "print_hide": 1, - "show_days": 1, - "show_seconds": 1 + "print_hide": 1 }, { "collapsible": 1, "collapsible_depends_on": "eval:(!doc.is_return)", "fieldname": "payment_schedule_section", "fieldtype": "Section Break", - "label": "Payment Terms", - "show_days": 1, - "show_seconds": 1 + "label": "Payment Terms" }, { "fieldname": "payment_terms_template", "fieldtype": "Link", "label": "Payment Terms Template", - "options": "Payment Terms Template", - "show_days": 1, - "show_seconds": 1 + "options": "Payment Terms Template" }, { "fieldname": "payment_schedule", @@ -1335,9 +1097,7 @@ "label": "Payment Schedule", "no_copy": 1, "options": "Payment Schedule", - "print_hide": 1, - "show_days": 1, - "show_seconds": 1 + "print_hide": 1 }, { "collapsible": 1, @@ -1345,33 +1105,25 @@ "fieldname": "terms_section_break", "fieldtype": "Section Break", "label": "Terms and Conditions", - "options": "fa fa-legal", - "show_days": 1, - "show_seconds": 1 + "options": "fa fa-legal" }, { "fieldname": "tc_name", "fieldtype": "Link", "label": "Terms", "options": "Terms and Conditions", - "print_hide": 1, - "show_days": 1, - "show_seconds": 1 + "print_hide": 1 }, { "fieldname": "terms", "fieldtype": "Text Editor", - "label": "Terms and Conditions1", - "show_days": 1, - "show_seconds": 1 + "label": "Terms and Conditions1" }, { "collapsible": 1, "fieldname": "printing_settings", "fieldtype": "Section Break", - "label": "Printing Settings", - "show_days": 1, - "show_seconds": 1 + "label": "Printing Settings" }, { "allow_on_submit": 1, @@ -1379,9 +1131,7 @@ "fieldtype": "Link", "label": "Letter Head", "options": "Letter Head", - "print_hide": 1, - "show_days": 1, - "show_seconds": 1 + "print_hide": 1 }, { "allow_on_submit": 1, @@ -1389,15 +1139,11 @@ "fieldname": "group_same_items", "fieldtype": "Check", "label": "Group same items", - "print_hide": 1, - "show_days": 1, - "show_seconds": 1 + "print_hide": 1 }, { "fieldname": "column_break_112", - "fieldtype": "Column Break", - "show_days": 1, - "show_seconds": 1 + "fieldtype": "Column Break" }, { "allow_on_submit": 1, @@ -1409,18 +1155,14 @@ "oldfieldtype": "Link", "options": "Print Heading", "print_hide": 1, - "report_hide": 1, - "show_days": 1, - "show_seconds": 1 + "report_hide": 1 }, { "fieldname": "language", "fieldtype": "Data", "label": "Print Language", "print_hide": 1, - "read_only": 1, - "show_days": 1, - "show_seconds": 1 + "read_only": 1 }, { "collapsible": 1, @@ -1429,9 +1171,16 @@ "label": "More Information", "oldfieldtype": "Section Break", "options": "fa fa-file-text", - "print_hide": 1, - "show_days": 1, - "show_seconds": 1 + "print_hide": 1 + }, + { + "default": "0", + "fetch_from": "supplier.is_internal_supplier", + "fieldname": "is_internal_supplier", + "fieldtype": "Check", + "ignore_user_permissions": 1, + "label": "Is Internal Supplier", + "read_only": 1 }, { "fieldname": "credit_to", @@ -1442,9 +1191,7 @@ "options": "Account", "print_hide": 1, "reqd": 1, - "search_index": 1, - "show_days": 1, - "show_seconds": 1 + "search_index": 1 }, { "fieldname": "party_account_currency", @@ -1454,21 +1201,17 @@ "no_copy": 1, "options": "Currency", "print_hide": 1, - "read_only": 1, - "show_days": 1, - "show_seconds": 1 + "read_only": 1 }, { "default": "No", "fieldname": "is_opening", "fieldtype": "Select", - "label": "Is Opening", + "label": "Is Opening Entry", "oldfieldname": "is_opening", "oldfieldtype": "Select", "options": "No\nYes", - "print_hide": 1, - "show_days": 1, - "show_seconds": 1 + "print_hide": 1 }, { "fieldname": "against_expense_account", @@ -1478,15 +1221,11 @@ "no_copy": 1, "oldfieldname": "against_expense_account", "oldfieldtype": "Small Text", - "print_hide": 1, - "show_days": 1, - "show_seconds": 1 + "print_hide": 1 }, { "fieldname": "column_break_63", - "fieldtype": "Column Break", - "show_days": 1, - "show_seconds": 1 + "fieldtype": "Column Break" }, { "default": "Draft", @@ -1494,10 +1233,8 @@ "fieldtype": "Select", "in_standard_filter": 1, "label": "Status", - "options": "\nDraft\nReturn\nDebit Note Issued\nSubmitted\nPaid\nUnpaid\nOverdue\nCancelled\nInternal Transfer", - "print_hide": 1, - "show_days": 1, - "show_seconds": 1 + "options": "\nDraft\nReturn\nDebit Note Issued\nSubmitted\nPaid\nPartly Paid\nUnpaid\nOverdue\nCancelled\nInternal Transfer", + "print_hide": 1 }, { "fieldname": "inter_company_invoice_reference", @@ -1506,9 +1243,7 @@ "no_copy": 1, "options": "Sales Invoice", "print_hide": 1, - "read_only": 1, - "show_days": 1, - "show_seconds": 1 + "read_only": 1 }, { "fieldname": "remarks", @@ -1517,18 +1252,14 @@ "no_copy": 1, "oldfieldname": "remarks", "oldfieldtype": "Text", - "print_hide": 1, - "show_days": 1, - "show_seconds": 1 + "print_hide": 1 }, { "collapsible": 1, "fieldname": "subscription_section", "fieldtype": "Section Break", "label": "Subscription Section", - "print_hide": 1, - "show_days": 1, - "show_seconds": 1 + "print_hide": 1 }, { "allow_on_submit": 1, @@ -1537,9 +1268,7 @@ "fieldtype": "Date", "label": "From Date", "no_copy": 1, - "print_hide": 1, - "show_days": 1, - "show_seconds": 1 + "print_hide": 1 }, { "allow_on_submit": 1, @@ -1548,15 +1277,11 @@ "fieldtype": "Date", "label": "To Date", "no_copy": 1, - "print_hide": 1, - "show_days": 1, - "show_seconds": 1 + "print_hide": 1 }, { "fieldname": "column_break_114", - "fieldtype": "Column Break", - "show_days": 1, - "show_seconds": 1 + "fieldtype": "Column Break" }, { "fieldname": "auto_repeat", @@ -1565,42 +1290,24 @@ "no_copy": 1, "options": "Auto Repeat", "print_hide": 1, - "read_only": 1, - "show_days": 1, - "show_seconds": 1 + "read_only": 1 }, { "allow_on_submit": 1, "depends_on": "eval: doc.auto_repeat", "fieldname": "update_auto_repeat_reference", "fieldtype": "Button", - "label": "Update Auto Repeat Reference", - "show_days": 1, - "show_seconds": 1 + "label": "Update Auto Repeat Reference" }, { "collapsible": 1, "fieldname": "accounting_dimensions_section", "fieldtype": "Section Break", - "label": "Accounting Dimensions ", - "show_days": 1, - "show_seconds": 1 + "label": "Accounting Dimensions " }, { "fieldname": "dimension_col_break", - "fieldtype": "Column Break", - "show_days": 1, - "show_seconds": 1 - }, - { - "default": "0", - "fetch_from": "supplier.is_internal_supplier", - "fieldname": "is_internal_supplier", - "fieldtype": "Check", - "label": "Is Internal Supplier", - "read_only": 1, - "show_days": 1, - "show_seconds": 1 + "fieldtype": "Column Break" }, { "fieldname": "tax_withholding_category", @@ -1608,33 +1315,25 @@ "hidden": 1, "label": "Tax Withholding Category", "options": "Tax Withholding Category", - "print_hide": 1, - "show_days": 1, - "show_seconds": 1 + "print_hide": 1 }, { "fieldname": "billing_address", "fieldtype": "Link", "label": "Select Billing Address", - "options": "Address", - "show_days": 1, - "show_seconds": 1 + "options": "Address" }, { "fieldname": "billing_address_display", "fieldtype": "Small Text", "label": "Billing Address", - "read_only": 1, - "show_days": 1, - "show_seconds": 1 + "read_only": 1 }, { "fieldname": "project", "fieldtype": "Link", "label": "Project", - "options": "Project", - "show_days": 1, - "show_seconds": 1 + "options": "Project" }, { "depends_on": "eval:doc.is_internal_supplier", @@ -1642,9 +1341,7 @@ "fieldname": "unrealized_profit_loss_account", "fieldtype": "Link", "label": "Unrealized Profit / Loss Account", - "options": "Account", - "show_days": 1, - "show_seconds": 1 + "options": "Account" }, { "depends_on": "eval:doc.is_internal_supplier", @@ -1653,9 +1350,7 @@ "fieldname": "represents_company", "fieldtype": "Link", "label": "Represents Company", - "options": "Company", - "show_days": 1, - "show_seconds": 1 + "options": "Company" }, { "depends_on": "eval:doc.update_stock && doc.is_internal_supplier", @@ -1667,8 +1362,6 @@ "options": "Warehouse", "print_hide": 1, "print_width": "50px", - "show_days": 1, - "show_seconds": 1, "width": "50px" }, { @@ -1680,8 +1373,6 @@ "options": "Warehouse", "print_hide": 1, "print_width": "50px", - "show_days": 1, - "show_seconds": 1, "width": "50px" }, { @@ -1705,20 +1396,30 @@ "fieldtype": "Check", "hidden": 1, "label": "Ignore Default Payment Terms Template", - "read_only": 1, - "show_days": 1, - "show_seconds": 1 + "read_only": 1 + }, + { + "collapsible": 1, + "fieldname": "accounting_details_section", + "fieldtype": "Section Break", + "label": "Accounting Details", + "print_hide": 1 + }, + { + "fieldname": "column_break_147", + "fieldtype": "Column Break" } ], "icon": "fa fa-file-text", "idx": 204, "is_submittable": 1, "links": [], - "modified": "2021-08-17 20:16:12.737743", + "modified": "2021-10-12 20:55:16.145651", "modified_by": "Administrator", "module": "Accounts", "name": "Purchase Invoice", "name_case": "Title Case", + "naming_rule": "By \"Naming Series\" field", "owner": "Administrator", "permissions": [ { diff --git a/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.py b/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.py index 62cd90ee9fc..62e3dc83468 100644 --- a/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.py +++ b/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.py @@ -1,20 +1,19 @@ # Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors # License: GNU General Public License v3. See license.txt -# -*- coding: utf-8 -*- -from __future__ import unicode_literals import frappe from frappe import _, throw from frappe.model.mapper import get_mapped_doc from frappe.utils import cint, cstr, flt, formatdate, get_link_to_form, getdate, nowdate -from six import iteritems import erpnext from erpnext.accounts.deferred_revenue import validate_service_stop_date from erpnext.accounts.doctype.gl_entry.gl_entry import update_outstanding_amt from erpnext.accounts.doctype.sales_invoice.sales_invoice import ( check_if_return_invoice_linked_with_payment_entry, + get_total_in_party_account_currency, + is_overdue, unlink_inter_company_doc, update_linked_doc, validate_inter_company_party, @@ -600,7 +599,7 @@ class PurchaseInvoice(BuyingController): # Amount added through landed-cost-voucher if landed_cost_entries: - for account, amount in iteritems(landed_cost_entries[(item.item_code, item.name)]): + for account, amount in landed_cost_entries[(item.item_code, item.name)].items(): gl_entries.append(self.get_gl_dict({ "account": account, "against": item.expense_account, @@ -1145,6 +1144,12 @@ class PurchaseInvoice(BuyingController): if not self.apply_tds: return + if self.apply_tds and not self.get('tax_withholding_category'): + self.tax_withholding_category = frappe.db.get_value('Supplier', self.supplier, 'tax_withholding_category') + + if not self.tax_withholding_category: + return + tax_withholding_details = get_party_tax_withholding_details(self, self.tax_withholding_category) if not tax_withholding_details: @@ -1175,10 +1180,8 @@ class PurchaseInvoice(BuyingController): self.status = 'Draft' return - precision = self.precision("outstanding_amount") - outstanding_amount = flt(self.outstanding_amount, precision) - due_date = getdate(self.due_date) - nowdate = getdate() + outstanding_amount = flt(self.outstanding_amount, self.precision("outstanding_amount")) + total = get_total_in_party_account_currency(self) if not status: if self.docstatus == 2: @@ -1186,9 +1189,11 @@ class PurchaseInvoice(BuyingController): elif self.docstatus == 1: if self.is_internal_transfer(): self.status = 'Internal Transfer' - elif outstanding_amount > 0 and due_date < nowdate: + elif is_overdue(self, total): self.status = "Overdue" - elif outstanding_amount > 0 and due_date >= nowdate: + elif 0 < outstanding_amount < total: + self.status = "Partly Paid" + elif outstanding_amount > 0 and getdate(self.due_date) >= getdate(): self.status = "Unpaid" #Check if outstanding amount is 0 due to debit note issued against invoice elif outstanding_amount <= 0 and self.is_return == 0 and frappe.db.get_value('Purchase Invoice', {'is_return': 1, 'return_against': self.name, 'docstatus': 1}): diff --git a/erpnext/accounts/doctype/purchase_invoice/purchase_invoice_dashboard.py b/erpnext/accounts/doctype/purchase_invoice/purchase_invoice_dashboard.py index 4cc319d594f..76c9fcdd7cb 100644 --- a/erpnext/accounts/doctype/purchase_invoice/purchase_invoice_dashboard.py +++ b/erpnext/accounts/doctype/purchase_invoice/purchase_invoice_dashboard.py @@ -1,5 +1,3 @@ -from __future__ import unicode_literals - from frappe import _ diff --git a/erpnext/accounts/doctype/purchase_invoice/purchase_invoice_list.js b/erpnext/accounts/doctype/purchase_invoice/purchase_invoice_list.js index 771b49ac629..f6ff83add8c 100644 --- a/erpnext/accounts/doctype/purchase_invoice/purchase_invoice_list.js +++ b/erpnext/accounts/doctype/purchase_invoice/purchase_invoice_list.js @@ -2,28 +2,58 @@ // License: GNU General Public License v3. See license.txt // render -frappe.listview_settings['Purchase Invoice'] = { - add_fields: ["supplier", "supplier_name", "base_grand_total", "outstanding_amount", "due_date", "company", - "currency", "is_return", "release_date", "on_hold", "represents_company", "is_internal_supplier"], - get_indicator: function(doc) { - if ((flt(doc.outstanding_amount) <= 0) && doc.docstatus == 1 && doc.status == 'Debit Note Issued') { - return [__("Debit Note Issued"), "darkgrey", "outstanding_amount,<=,0"]; - } else if (flt(doc.outstanding_amount) > 0 && doc.docstatus==1) { - if(cint(doc.on_hold) && !doc.release_date) { - return [__("On Hold"), "darkgrey"]; - } else if (cint(doc.on_hold) && doc.release_date && frappe.datetime.get_diff(doc.release_date, frappe.datetime.nowdate()) > 0) { - return [__("Temporarily on Hold"), "darkgrey"]; - } else if (frappe.datetime.get_diff(doc.due_date) < 0) { - return [__("Overdue"), "red", "outstanding_amount,>,0|due_date,<,Today"]; - } else { - return [__("Unpaid"), "orange", "outstanding_amount,>,0|due_date,>=,Today"]; - } - } else if (cint(doc.is_return)) { - return [__("Return"), "gray", "is_return,=,Yes"]; - } else if (doc.company == doc.represents_company && doc.is_internal_supplier) { - return [__("Internal Transfer"), "darkgrey", "outstanding_amount,=,0"]; - } else if (flt(doc.outstanding_amount)==0 && doc.docstatus==1) { - return [__("Paid"), "green", "outstanding_amount,=,0"]; +frappe.listview_settings["Purchase Invoice"] = { + add_fields: [ + "supplier", + "supplier_name", + "base_grand_total", + "outstanding_amount", + "due_date", + "company", + "currency", + "is_return", + "release_date", + "on_hold", + "represents_company", + "is_internal_supplier", + ], + get_indicator(doc) { + if (doc.status == "Debit Note Issued") { + return [__(doc.status), "darkgrey", "status,=," + doc.status]; } - } + + if ( + flt(doc.outstanding_amount) > 0 && + doc.docstatus == 1 && + cint(doc.on_hold) + ) { + if (!doc.release_date) { + return [__("On Hold"), "darkgrey"]; + } else if ( + frappe.datetime.get_diff( + doc.release_date, + frappe.datetime.nowdate() + ) > 0 + ) { + return [__("Temporarily on Hold"), "darkgrey"]; + } + } + + const status_colors = { + "Unpaid": "orange", + "Paid": "green", + "Return": "gray", + "Overdue": "red", + "Partly Paid": "yellow", + "Internal Transfer": "darkgrey", + }; + + if (status_colors[doc.status]) { + return [ + __(doc.status), + status_colors[doc.status], + "status,=," + doc.status, + ]; + } + }, }; diff --git a/erpnext/accounts/doctype/purchase_invoice/test_purchase_invoice.py b/erpnext/accounts/doctype/purchase_invoice/test_purchase_invoice.py index 20d6c466e4c..78396a5e589 100644 --- a/erpnext/accounts/doctype/purchase_invoice/test_purchase_invoice.py +++ b/erpnext/accounts/doctype/purchase_invoice/test_purchase_invoice.py @@ -2,7 +2,6 @@ # License: GNU General Public License v3. See license.txt -from __future__ import unicode_literals import unittest @@ -14,6 +13,7 @@ from erpnext.accounts.doctype.account.test_account import create_account, get_in from erpnext.accounts.doctype.payment_entry.payment_entry import get_payment_entry from erpnext.buying.doctype.supplier.test_supplier import create_supplier from erpnext.controllers.accounts_controller import get_payment_terms +from erpnext.controllers.buying_controller import QtyMismatchError from erpnext.exceptions import InvalidCurrency from erpnext.projects.doctype.project.test_project import make_project from erpnext.stock.doctype.item.test_item import create_item @@ -36,6 +36,27 @@ class TestPurchaseInvoice(unittest.TestCase): def tearDownClass(self): unlink_payment_on_cancel_of_invoice(0) + def test_purchase_invoice_received_qty(self): + """ + 1. Test if received qty is validated against accepted + rejected + 2. Test if received qty is auto set on save + """ + pi = make_purchase_invoice( + qty=1, + rejected_qty=1, + received_qty=3, + item_code="_Test Item Home Desktop 200", + rejected_warehouse = "_Test Rejected Warehouse - _TC", + update_stock=True, do_not_save=True) + self.assertRaises(QtyMismatchError, pi.save) + + pi.items[0].received_qty = 0 + pi.save() + self.assertEqual(pi.items[0].received_qty, 2) + + # teardown + pi.delete() + def test_gl_entries_without_perpetual_inventory(self): frappe.db.set_value("Company", "_Test Company", "round_off_account", "Round Off - _TC") pi = frappe.copy_doc(test_records[0]) @@ -812,29 +833,12 @@ class TestPurchaseInvoice(unittest.TestCase): pi.shipping_rule = shipping_rule.name pi.insert() - - shipping_amount = 0.0 - for condition in shipping_rule.get("conditions"): - if not condition.to_value or (flt(condition.from_value) <= pi.net_total <= flt(condition.to_value)): - shipping_amount = condition.shipping_amount - - shipping_charge = { - "doctype": "Purchase Taxes and Charges", - "category": "Valuation and Total", - "charge_type": "Actual", - "account_head": shipping_rule.account, - "cost_center": shipping_rule.cost_center, - "tax_amount": shipping_amount, - "description": shipping_rule.name, - "add_deduct_tax": "Add" - } - pi.append("taxes", shipping_charge) pi.save() self.assertEqual(pi.net_total, 1250) - self.assertEqual(pi.total_taxes_and_charges, 462.3) - self.assertEqual(pi.grand_total, 1712.3) + self.assertEqual(pi.total_taxes_and_charges, 354.1) + self.assertEqual(pi.grand_total, 1604.1) def test_make_pi_without_terms(self): pi = make_purchase_invoice(do_not_save=1) @@ -1151,10 +1155,11 @@ class TestPurchaseInvoice(unittest.TestCase): tax_withholding_category = 'TDS - 194 - Dividends - Individual') # Update tax withholding category with current fiscal year and rate details - update_tax_witholding_category('_Test Company', 'TDS Payable - _TC', nowdate()) + update_tax_witholding_category('_Test Company', 'TDS Payable - _TC') # Create Purchase Order with TDS applied - po = create_purchase_order(do_not_save=1, supplier=supplier.name, rate=3000, item='_Test Non Stock Item') + po = create_purchase_order(do_not_save=1, supplier=supplier.name, rate=3000, item='_Test Non Stock Item', + posting_date='2021-09-15') po.apply_tds = 1 po.tax_withholding_category = 'TDS - 194 - Dividends - Individual' po.save() @@ -1226,16 +1231,20 @@ def check_gl_entries(doc, voucher_no, expected_gle, posting_date): doc.assertEqual(expected_gle[i][2], gle.credit) doc.assertEqual(getdate(expected_gle[i][3]), gle.posting_date) -def update_tax_witholding_category(company, account, date): +def update_tax_witholding_category(company, account): from erpnext.accounts.utils import get_fiscal_year - fiscal_year = get_fiscal_year(date=date, company=company) + fiscal_year = get_fiscal_year(fiscal_year='2021') if not frappe.db.get_value('Tax Withholding Rate', - {'parent': 'TDS - 194 - Dividends - Individual', 'fiscal_year': fiscal_year[0]}): + {'parent': 'TDS - 194 - Dividends - Individual', 'from_date': ('>=', fiscal_year[1]), + 'to_date': ('<=', fiscal_year[2])}): tds_category = frappe.get_doc('Tax Withholding Category', 'TDS - 194 - Dividends - Individual') + tds_category.set('rates', []) + tds_category.append('rates', { - 'fiscal_year': fiscal_year[0], + 'from_date': fiscal_year[1], + 'to_date': fiscal_year[2], 'tax_withholding_rate': 10, 'single_threshold': 2500, 'cumulative_threshold': 0 diff --git a/erpnext/accounts/doctype/purchase_invoice_advance/__init__.py b/erpnext/accounts/doctype/purchase_invoice_advance/__init__.py index baffc488252..e69de29bb2d 100644 --- a/erpnext/accounts/doctype/purchase_invoice_advance/__init__.py +++ b/erpnext/accounts/doctype/purchase_invoice_advance/__init__.py @@ -1 +0,0 @@ -from __future__ import unicode_literals diff --git a/erpnext/accounts/doctype/purchase_invoice_advance/purchase_invoice_advance.json b/erpnext/accounts/doctype/purchase_invoice_advance/purchase_invoice_advance.json index 63dfff8921f..9fcbf5c6339 100644 --- a/erpnext/accounts/doctype/purchase_invoice_advance/purchase_invoice_advance.json +++ b/erpnext/accounts/doctype/purchase_invoice_advance/purchase_invoice_advance.json @@ -97,6 +97,7 @@ "width": "100px" }, { + "depends_on": "exchange_gain_loss", "fieldname": "exchange_gain_loss", "fieldtype": "Currency", "label": "Exchange Gain/Loss", @@ -104,6 +105,7 @@ "read_only": 1 }, { + "depends_on": "exchange_gain_loss", "fieldname": "ref_exchange_rate", "fieldtype": "Float", "label": "Reference Exchange Rate", @@ -115,7 +117,7 @@ "index_web_pages_for_search": 1, "istable": 1, "links": [], - "modified": "2021-04-20 16:26:53.820530", + "modified": "2021-09-26 15:47:28.167371", "modified_by": "Administrator", "module": "Accounts", "name": "Purchase Invoice Advance", diff --git a/erpnext/accounts/doctype/purchase_invoice_advance/purchase_invoice_advance.py b/erpnext/accounts/doctype/purchase_invoice_advance/purchase_invoice_advance.py index ec2ce65168d..44e1f6d5685 100644 --- a/erpnext/accounts/doctype/purchase_invoice_advance/purchase_invoice_advance.py +++ b/erpnext/accounts/doctype/purchase_invoice_advance/purchase_invoice_advance.py @@ -1,7 +1,6 @@ # Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors # License: GNU General Public License v3. See license.txt -from __future__ import unicode_literals from frappe.model.document import Document diff --git a/erpnext/accounts/doctype/purchase_invoice_item/__init__.py b/erpnext/accounts/doctype/purchase_invoice_item/__init__.py index baffc488252..e69de29bb2d 100644 --- a/erpnext/accounts/doctype/purchase_invoice_item/__init__.py +++ b/erpnext/accounts/doctype/purchase_invoice_item/__init__.py @@ -1 +0,0 @@ -from __future__ import unicode_literals diff --git a/erpnext/accounts/doctype/purchase_invoice_item/purchase_invoice_item.json b/erpnext/accounts/doctype/purchase_invoice_item/purchase_invoice_item.json index d39a9fc058d..f9b2efd053b 100644 --- a/erpnext/accounts/doctype/purchase_invoice_item/purchase_invoice_item.json +++ b/erpnext/accounts/doctype/purchase_invoice_item/purchase_invoice_item.json @@ -22,10 +22,10 @@ "received_qty", "qty", "rejected_qty", - "stock_uom", "col_break2", "uom", "conversion_factor", + "stock_uom", "stock_qty", "sec_break1", "price_list_rate", @@ -175,7 +175,8 @@ { "fieldname": "received_qty", "fieldtype": "Float", - "label": "Received Qty" + "label": "Received Qty", + "read_only": 1 }, { "bold": 1, @@ -223,7 +224,7 @@ { "fieldname": "stock_qty", "fieldtype": "Float", - "label": "Stock Qty", + "label": "Accepted Qty in Stock UOM", "print_hide": 1, "read_only": 1, "reqd": 1 @@ -870,10 +871,11 @@ "idx": 1, "istable": 1, "links": [], - "modified": "2021-09-01 16:04:03.538643", + "modified": "2021-11-15 17:04:07.191013", "modified_by": "Administrator", "module": "Accounts", "name": "Purchase Invoice Item", + "naming_rule": "Random", "owner": "Administrator", "permissions": [], "sort_field": "modified", diff --git a/erpnext/accounts/doctype/purchase_invoice_item/purchase_invoice_item.py b/erpnext/accounts/doctype/purchase_invoice_item/purchase_invoice_item.py index ad2a24c0e2f..0e3c723178b 100644 --- a/erpnext/accounts/doctype/purchase_invoice_item/purchase_invoice_item.py +++ b/erpnext/accounts/doctype/purchase_invoice_item/purchase_invoice_item.py @@ -1,7 +1,6 @@ # Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors # License: GNU General Public License v3. See license.txt -from __future__ import unicode_literals from frappe.model.document import Document diff --git a/erpnext/accounts/doctype/purchase_taxes_and_charges/__init__.py b/erpnext/accounts/doctype/purchase_taxes_and_charges/__init__.py index baffc488252..e69de29bb2d 100644 --- a/erpnext/accounts/doctype/purchase_taxes_and_charges/__init__.py +++ b/erpnext/accounts/doctype/purchase_taxes_and_charges/__init__.py @@ -1 +0,0 @@ -from __future__ import unicode_literals diff --git a/erpnext/accounts/doctype/purchase_taxes_and_charges/purchase_taxes_and_charges.py b/erpnext/accounts/doctype/purchase_taxes_and_charges/purchase_taxes_and_charges.py index 34ac25753b3..262e7ebb5b6 100644 --- a/erpnext/accounts/doctype/purchase_taxes_and_charges/purchase_taxes_and_charges.py +++ b/erpnext/accounts/doctype/purchase_taxes_and_charges/purchase_taxes_and_charges.py @@ -1,7 +1,6 @@ # Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors # License: GNU General Public License v3. See license.txt -from __future__ import unicode_literals from frappe.model.document import Document diff --git a/erpnext/accounts/doctype/purchase_taxes_and_charges_template/purchase_taxes_and_charges_template.py b/erpnext/accounts/doctype/purchase_taxes_and_charges_template/purchase_taxes_and_charges_template.py index 53b549f6829..f5eb404d0a4 100644 --- a/erpnext/accounts/doctype/purchase_taxes_and_charges_template/purchase_taxes_and_charges_template.py +++ b/erpnext/accounts/doctype/purchase_taxes_and_charges_template/purchase_taxes_and_charges_template.py @@ -1,8 +1,6 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors # License: GNU General Public License v3. See license.txt -from __future__ import unicode_literals import frappe from frappe.model.document import Document diff --git a/erpnext/accounts/doctype/purchase_taxes_and_charges_template/purchase_taxes_and_charges_template_dashboard.py b/erpnext/accounts/doctype/purchase_taxes_and_charges_template/purchase_taxes_and_charges_template_dashboard.py index db9793d77a6..3176556ec53 100644 --- a/erpnext/accounts/doctype/purchase_taxes_and_charges_template/purchase_taxes_and_charges_template_dashboard.py +++ b/erpnext/accounts/doctype/purchase_taxes_and_charges_template/purchase_taxes_and_charges_template_dashboard.py @@ -1,5 +1,3 @@ -from __future__ import unicode_literals - from frappe import _ diff --git a/erpnext/accounts/doctype/purchase_taxes_and_charges_template/test_purchase_taxes_and_charges_template.py b/erpnext/accounts/doctype/purchase_taxes_and_charges_template/test_purchase_taxes_and_charges_template.py index c60c81b7239..b5b4a67d759 100644 --- a/erpnext/accounts/doctype/purchase_taxes_and_charges_template/test_purchase_taxes_and_charges_template.py +++ b/erpnext/accounts/doctype/purchase_taxes_and_charges_template/test_purchase_taxes_and_charges_template.py @@ -1,7 +1,5 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors and Contributors # See license.txt -from __future__ import unicode_literals import unittest diff --git a/erpnext/accounts/doctype/salary_component_account/salary_component_account.py b/erpnext/accounts/doctype/salary_component_account/salary_component_account.py index d96ef62c293..b70179aa912 100644 --- a/erpnext/accounts/doctype/salary_component_account/salary_component_account.py +++ b/erpnext/accounts/doctype/salary_component_account/salary_component_account.py @@ -1,8 +1,6 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and contributors # For license information, please see license.txt -from __future__ import unicode_literals from frappe.model.document import Document diff --git a/erpnext/accounts/doctype/sales_invoice/__init__.py b/erpnext/accounts/doctype/sales_invoice/__init__.py index baffc488252..e69de29bb2d 100644 --- a/erpnext/accounts/doctype/sales_invoice/__init__.py +++ b/erpnext/accounts/doctype/sales_invoice/__init__.py @@ -1 +0,0 @@ -from __future__ import unicode_literals diff --git a/erpnext/accounts/doctype/sales_invoice/sales_invoice.js b/erpnext/accounts/doctype/sales_invoice/sales_invoice.js index 2cb9acfa2a9..a1f3ee4b063 100644 --- a/erpnext/accounts/doctype/sales_invoice/sales_invoice.js +++ b/erpnext/accounts/doctype/sales_invoice/sales_invoice.js @@ -12,6 +12,22 @@ erpnext.accounts.SalesInvoiceController = class SalesInvoiceController extends e } company() { erpnext.accounts.dimensions.update_dimension(this.frm, this.frm.doctype); + + let me = this; + if (this.frm.doc.company) { + frappe.call({ + method: + "erpnext.accounts.party.get_party_account", + args: { + party_type: 'Customer', + party: this.frm.doc.customer, + company: this.frm.doc.company + }, + callback: (response) => { + if (response) me.frm.set_value("debit_to", response.message); + }, + }); + } } onload() { var me = this; @@ -445,15 +461,6 @@ erpnext.accounts.SalesInvoiceController = class SalesInvoiceController extends e this.frm.refresh_field("base_paid_amount"); } - currency() { - this._super(); - $.each(cur_frm.doc.timesheets, function(i, d) { - let row = frappe.get_doc(d.doctype, d.name) - set_timesheet_detail_rate(row.doctype, row.name, cur_frm.doc.currency, row.timesheet_detail) - }); - calculate_total_billing_amount(cur_frm) - } - currency() { var me = this; super.currency(); @@ -462,7 +469,7 @@ erpnext.accounts.SalesInvoiceController = class SalesInvoiceController extends e let row = frappe.get_doc(d.doctype, d.name) set_timesheet_detail_rate(row.doctype, row.name, me.frm.doc.currency, row.timesheet_detail) }); - calculate_total_billing_amount(this.frm); + frm.trigger("calculate_timesheet_totals"); } } }; @@ -734,19 +741,6 @@ frappe.ui.form.on('Sales Invoice', { } }, - project: function(frm){ - if (!frm.doc.is_return) { - frm.call({ - method: "add_timesheet_data", - doc: frm.doc, - callback: function(r, rt) { - refresh_field(['timesheets']) - } - }) - frm.refresh(); - } - }, - onload: function(frm) { frm.redemption_conversion_factor = null; }, @@ -857,25 +851,92 @@ frappe.ui.form.on('Sales Invoice', { } }, - add_timesheet_row: function(frm, row, exchange_rate) { - frm.add_child('timesheets', { - 'activity_type': row.activity_type, - 'description': row.description, - 'time_sheet': row.parent, - 'billing_hours': row.billing_hours, - 'billing_amount': flt(row.billing_amount) * flt(exchange_rate), - 'timesheet_detail': row.name, - 'project_name': row.project_name + project: function(frm) { + if (frm.doc.project) { + frm.events.add_timesheet_data(frm, { + project: frm.doc.project + }); + } + }, + + async add_timesheet_data(frm, kwargs) { + if (kwargs === "Sales Invoice") { + // called via frm.trigger() + kwargs = Object(); + } + + if (!kwargs.hasOwnProperty("project") && frm.doc.project) { + kwargs.project = frm.doc.project; + } + + const timesheets = await frm.events.get_timesheet_data(frm, kwargs); + return frm.events.set_timesheet_data(frm, timesheets); + }, + + async get_timesheet_data(frm, kwargs) { + return frappe.call({ + method: "erpnext.projects.doctype.timesheet.timesheet.get_projectwise_timesheet_data", + args: kwargs + }).then(r => { + if (!r.exc && r.message.length > 0) { + return r.message + } else { + return [] + } }); - frm.refresh_field('timesheets'); - calculate_total_billing_amount(frm); + }, + + set_timesheet_data: function(frm, timesheets) { + frm.clear_table("timesheets") + timesheets.forEach(timesheet => { + if (frm.doc.currency != timesheet.currency) { + frappe.call({ + method: "erpnext.setup.utils.get_exchange_rate", + args: { + from_currency: timesheet.currency, + to_currency: frm.doc.currency + }, + callback: function(r) { + if (r.message) { + exchange_rate = r.message; + frm.events.append_time_log(frm, timesheet, exchange_rate); + } + } + }); + } else { + frm.events.append_time_log(frm, timesheet, 1.0); + } + }); + }, + + append_time_log: function(frm, time_log, exchange_rate) { + const row = frm.add_child("timesheets"); + row.activity_type = time_log.activity_type; + row.description = time_log.description; + row.time_sheet = time_log.time_sheet; + row.from_time = time_log.from_time; + row.to_time = time_log.to_time; + row.billing_hours = time_log.billing_hours; + row.billing_amount = flt(time_log.billing_amount) * flt(exchange_rate); + row.timesheet_detail = time_log.name; + row.project_name = time_log.project_name; + + frm.refresh_field("timesheets"); + frm.trigger("calculate_timesheet_totals"); + }, + + calculate_timesheet_totals: function(frm) { + frm.set_value("total_billing_amount", + frm.doc.timesheets.reduce((a, b) => a + (b["billing_amount"] || 0.0), 0.0)); + frm.set_value("total_billing_hours", + frm.doc.timesheets.reduce((a, b) => a + (b["billing_hours"] || 0.0), 0.0)); }, refresh: function(frm) { if (frm.doc.docstatus===0 && !frm.doc.is_return) { - frm.add_custom_button(__('Fetch Timesheet'), function() { + frm.add_custom_button(__("Fetch Timesheet"), function() { let d = new frappe.ui.Dialog({ - title: __('Fetch Timesheet'), + title: __("Fetch Timesheet"), fields: [ { "label" : __("From"), @@ -884,8 +945,8 @@ frappe.ui.form.on('Sales Invoice', { "reqd": 1, }, { - fieldtype: 'Column Break', - fieldname: 'col_break_1', + fieldtype: "Column Break", + fieldname: "col_break_1", }, { "label" : __("To"), @@ -902,48 +963,18 @@ frappe.ui.form.on('Sales Invoice', { }, ], primary_action: function() { - let data = d.get_values(); - frappe.call({ - method: "erpnext.projects.doctype.timesheet.timesheet.get_projectwise_timesheet_data", - args: { - from_time: data.from_time, - to_time: data.to_time, - project: data.project - }, - callback: function(r) { - if (!r.exc && r.message.length > 0) { - frm.clear_table('timesheets') - r.message.forEach((d) => { - let exchange_rate = 1.0; - if (frm.doc.currency != d.currency) { - frappe.call({ - method: 'erpnext.setup.utils.get_exchange_rate', - args: { - from_currency: d.currency, - to_currency: frm.doc.currency - }, - callback: function(r) { - if (r.message) { - exchange_rate = r.message; - frm.events.add_timesheet_row(frm, d, exchange_rate); - } - } - }); - } else { - frm.events.add_timesheet_row(frm, d, exchange_rate); - } - }); - } else { - frappe.msgprint(__('No Timesheets found with the selected filters.')) - } - d.hide(); - } + const data = d.get_values(); + frm.events.add_timesheet_data(frm, { + from_time: data.from_time, + to_time: data.to_time, + project: data.project }); + d.hide(); }, - primary_action_label: __('Get Timesheets') + primary_action_label: __("Get Timesheets") }); d.show(); - }) + }); } if (frm.doc.is_debit_note) { @@ -976,26 +1007,20 @@ frappe.ui.form.on('Sales Invoice', { frm: frm }); }, + create_dunning: function(frm) { frappe.model.open_mapped_doc({ method: "erpnext.accounts.doctype.sales_invoice.sales_invoice.create_dunning", frm: frm }); } -}) +}); -var calculate_total_billing_amount = function(frm) { - var doc = frm.doc; - - doc.total_billing_amount = 0.0 - if (doc.timesheets) { - doc.timesheets.forEach((d) => { - doc.total_billing_amount += flt(d.billing_amount) - }); +frappe.ui.form.on("Sales Invoice Timesheet", { + timesheets_remove(frm) { + frm.trigger("calculate_timesheet_totals"); } - - refresh_field('total_billing_amount') -} +}); var set_timesheet_detail_rate = function(cdt, cdn, currency, timelog) { frappe.call({ @@ -1042,276 +1067,3 @@ var select_loyalty_program = function(frm, loyalty_programs) { dialog.show(); } - -// Healthcare -var get_healthcare_services_to_invoice = function(frm) { - var me = this; - let selected_patient = ''; - var dialog = new frappe.ui.Dialog({ - title: __("Get Items from Healthcare Services"), - fields:[ - { - fieldtype: 'Link', - options: 'Patient', - label: 'Patient', - fieldname: "patient", - reqd: true - }, - { fieldtype: 'Section Break' }, - { fieldtype: 'HTML', fieldname: 'results_area' } - ] - }); - var $wrapper; - var $results; - var $placeholder; - dialog.set_values({ - 'patient': frm.doc.patient - }); - dialog.fields_dict["patient"].df.onchange = () => { - var patient = dialog.fields_dict.patient.input.value; - if(patient && patient!=selected_patient){ - selected_patient = patient; - var method = "erpnext.healthcare.utils.get_healthcare_services_to_invoice"; - var args = {patient: patient, company: frm.doc.company}; - var columns = (["service", "reference_name", "reference_type"]); - get_healthcare_items(frm, true, $results, $placeholder, method, args, columns); - } - else if(!patient){ - selected_patient = ''; - $results.empty(); - $results.append($placeholder); - } - } - $wrapper = dialog.fields_dict.results_area.$wrapper.append(`
`); - $results = $wrapper.find('.results'); - $placeholder = $(`
- - -

No billable Healthcare Services found

-
-
`); - $results.on('click', '.list-item--head :checkbox', (e) => { - $results.find('.list-item-container .list-row-check') - .prop("checked", ($(e.target).is(':checked'))); - }); - set_primary_action(frm, dialog, $results, true); - dialog.show(); -}; - -var get_healthcare_items = function(frm, invoice_healthcare_services, $results, $placeholder, method, args, columns) { - var me = this; - $results.empty(); - frappe.call({ - method: method, - args: args, - callback: function(data) { - if(data.message){ - $results.append(make_list_row(columns, invoice_healthcare_services)); - for(let i=0; i - ${ - head ? `${__(frappe.model.unscrub(column))}` - - :(column !== "name" ? `${__(result[column])}` - : ` - ${__(result[column])}`) - } - `; - }) - - let $row = $(`
-
- -
- ${contents} -
`); - - $row = list_row_data_items(head, $row, result, invoice_healthcare_services); - return $row; -}; - -var set_primary_action= function(frm, dialog, $results, invoice_healthcare_services) { - var me = this; - dialog.set_primary_action(__('Add'), function() { - let checked_values = get_checked_values($results); - if(checked_values.length > 0){ - if(invoice_healthcare_services) { - frm.set_value("patient", dialog.fields_dict.patient.input.value); - } - frm.set_value("items", []); - add_to_item_line(frm, checked_values, invoice_healthcare_services); - dialog.hide(); - } - else{ - if(invoice_healthcare_services){ - frappe.msgprint(__("Please select Healthcare Service")); - } - else{ - frappe.msgprint(__("Please select Drug")); - } - } - }); -}; - -var get_checked_values= function($results) { - return $results.find('.list-item-container').map(function() { - let checked_values = {}; - if ($(this).find('.list-row-check:checkbox:checked').length > 0 ) { - checked_values['dn'] = $(this).attr('data-dn'); - checked_values['dt'] = $(this).attr('data-dt'); - checked_values['item'] = $(this).attr('data-item'); - if($(this).attr('data-rate') != 'undefined'){ - checked_values['rate'] = $(this).attr('data-rate'); - } - else{ - checked_values['rate'] = false; - } - if($(this).attr('data-income-account') != 'undefined'){ - checked_values['income_account'] = $(this).attr('data-income-account'); - } - else{ - checked_values['income_account'] = false; - } - if($(this).attr('data-qty') != 'undefined'){ - checked_values['qty'] = $(this).attr('data-qty'); - } - else{ - checked_values['qty'] = false; - } - if($(this).attr('data-description') != 'undefined'){ - checked_values['description'] = $(this).attr('data-description'); - } - else{ - checked_values['description'] = false; - } - return checked_values; - } - }).get(); -}; - -var get_drugs_to_invoice = function(frm) { - var me = this; - let selected_encounter = ''; - var dialog = new frappe.ui.Dialog({ - title: __("Get Items from Prescriptions"), - fields:[ - { fieldtype: 'Link', options: 'Patient', label: 'Patient', fieldname: "patient", reqd: true }, - { fieldtype: 'Link', options: 'Patient Encounter', label: 'Patient Encounter', fieldname: "encounter", reqd: true, - description:'Quantity will be calculated only for items which has "Nos" as UoM. You may change as required for each invoice item.', - get_query: function(doc) { - return { - filters: { - patient: dialog.get_value("patient"), - company: frm.doc.company, - docstatus: 1 - } - }; - } - }, - { fieldtype: 'Section Break' }, - { fieldtype: 'HTML', fieldname: 'results_area' } - ] - }); - var $wrapper; - var $results; - var $placeholder; - dialog.set_values({ - 'patient': frm.doc.patient, - 'encounter': "" - }); - dialog.fields_dict["encounter"].df.onchange = () => { - var encounter = dialog.fields_dict.encounter.input.value; - if(encounter && encounter!=selected_encounter){ - selected_encounter = encounter; - var method = "erpnext.healthcare.utils.get_drugs_to_invoice"; - var args = {encounter: encounter}; - var columns = (["drug_code", "quantity", "description"]); - get_healthcare_items(frm, false, $results, $placeholder, method, args, columns); - } - else if(!encounter){ - selected_encounter = ''; - $results.empty(); - $results.append($placeholder); - } - } - $wrapper = dialog.fields_dict.results_area.$wrapper.append(`
`); - $results = $wrapper.find('.results'); - $placeholder = $(`
- - -

No Drug Prescription found

-
-
`); - $results.on('click', '.list-item--head :checkbox', (e) => { - $results.find('.list-item-container .list-row-check') - .prop("checked", ($(e.target).is(':checked'))); - }); - set_primary_action(frm, dialog, $results, false); - dialog.show(); -}; - -var list_row_data_items = function(head, $row, result, invoice_healthcare_services) { - if(invoice_healthcare_services){ - head ? $row.addClass('list-item--head') - : $row = $(`
-
`).append($row); - } - else{ - head ? $row.addClass('list-item--head') - : $row = $(`
-
`).append($row); - } - return $row -}; - -var add_to_item_line = function(frm, checked_values, invoice_healthcare_services){ - if(invoice_healthcare_services){ - frappe.call({ - doc: frm.doc, - method: "set_healthcare_services", - args:{ - checked_values: checked_values - }, - callback: function() { - frm.trigger("validate"); - frm.refresh_fields(); - } - }); - } - else{ - for(let i=0; i 1){ - frappe.model.set_value(si_item.doctype, si_item.name, 'qty', parseFloat(checked_values[i]['qty'])); - } - } - frm.refresh_fields(); - } -}; diff --git a/erpnext/accounts/doctype/sales_invoice/sales_invoice.json b/erpnext/accounts/doctype/sales_invoice/sales_invoice.json index b5620ae6a96..93e32f1a18c 100644 --- a/erpnext/accounts/doctype/sales_invoice/sales_invoice.json +++ b/erpnext/accounts/doctype/sales_invoice/sales_invoice.json @@ -74,6 +74,7 @@ "time_sheet_list", "timesheets", "total_billing_amount", + "total_billing_hours", "section_break_30", "total_qty", "base_total", @@ -123,6 +124,13 @@ "total_advance", "outstanding_amount", "disable_rounded_total", + "column_break4", + "write_off_amount", + "base_write_off_amount", + "write_off_outstanding_amount_automatically", + "column_break_74", + "write_off_account", + "write_off_cost_center", "advances_section", "allocate_advances_automatically", "get_advances", @@ -143,13 +151,6 @@ "column_break_90", "change_amount", "account_for_change_amount", - "column_break4", - "write_off_amount", - "base_write_off_amount", - "write_off_outstanding_amount_automatically", - "column_break_74", - "write_off_account", - "write_off_cost_center", "terms_section_break", "tc_name", "terms", @@ -160,14 +161,14 @@ "column_break_84", "language", "more_information", + "status", "inter_company_invoice_reference", - "is_internal_customer", "represents_company", "customer_group", "campaign", - "is_discounted", "col_break23", - "status", + "is_internal_customer", + "is_discounted", "source", "more_info", "debit_to", @@ -247,7 +248,7 @@ "depends_on": "customer", "fetch_from": "customer.customer_name", "fieldname": "customer_name", - "fieldtype": "Data", + "fieldtype": "Small Text", "hide_days": 1, "hide_seconds": 1, "in_global_search": 1, @@ -1061,6 +1062,7 @@ "hide_days": 1, "hide_seconds": 1, "label": "Apply Additional Discount On", + "length": 15, "options": "\nGrand Total\nNet Total", "print_hide": 1 }, @@ -1147,7 +1149,7 @@ { "description": "In Words will be visible once you save the Sales Invoice.", "fieldname": "base_in_words", - "fieldtype": "Data", + "fieldtype": "Small Text", "hide_days": 1, "hide_seconds": 1, "label": "In Words (Company Currency)", @@ -1207,7 +1209,7 @@ }, { "fieldname": "in_words", - "fieldtype": "Data", + "fieldtype": "Small Text", "hide_days": 1, "hide_seconds": 1, "label": "In Words", @@ -1560,6 +1562,7 @@ "hide_days": 1, "hide_seconds": 1, "label": "Print Language", + "length": 6, "print_hide": 1, "read_only": 1 }, @@ -1647,8 +1650,9 @@ "hide_seconds": 1, "in_standard_filter": 1, "label": "Status", + "length": 30, "no_copy": 1, - "options": "\nDraft\nReturn\nCredit Note Issued\nSubmitted\nPaid\nUnpaid\nUnpaid and Discounted\nOverdue and Discounted\nOverdue\nCancelled\nInternal Transfer", + "options": "\nDraft\nReturn\nCredit Note Issued\nSubmitted\nPaid\nPartly Paid\nUnpaid\nUnpaid and Discounted\nPartly Paid and Discounted\nOverdue and Discounted\nOverdue\nCancelled\nInternal Transfer", "print_hide": 1, "read_only": 1 }, @@ -1706,6 +1710,7 @@ "hide_days": 1, "hide_seconds": 1, "label": "Is Opening Entry", + "length": 4, "oldfieldname": "is_opening", "oldfieldtype": "Select", "options": "No\nYes", @@ -1717,6 +1722,7 @@ "hide_days": 1, "hide_seconds": 1, "label": "C-Form Applicable", + "length": 4, "no_copy": 1, "options": "No\nYes", "print_hide": 1 @@ -1948,6 +1954,7 @@ "fetch_from": "customer.represents_company", "fieldname": "represents_company", "fieldtype": "Link", + "ignore_user_permissions": 1, "label": "Represents Company", "options": "Company", "read_only": 1 @@ -2005,6 +2012,13 @@ "hidden": 1, "label": "Ignore Default Payment Terms Template", "read_only": 1 + }, + { + "fieldname": "total_billing_hours", + "fieldtype": "Float", + "label": "Total Billing Hours", + "print_hide": 1, + "read_only": 1 } ], "icon": "fa fa-file-text", @@ -2017,11 +2031,12 @@ "link_fieldname": "consolidated_invoice" } ], - "modified": "2021-08-27 20:13:40.456462", + "modified": "2021-10-11 20:19:38.667508", "modified_by": "Administrator", "module": "Accounts", "name": "Sales Invoice", "name_case": "Title Case", + "naming_rule": "By \"Naming Series\" field", "owner": "Administrator", "permissions": [ { diff --git a/erpnext/accounts/doctype/sales_invoice/sales_invoice.py b/erpnext/accounts/doctype/sales_invoice/sales_invoice.py index ec249c24194..59d46fc2e87 100644 --- a/erpnext/accounts/doctype/sales_invoice/sales_invoice.py +++ b/erpnext/accounts/doctype/sales_invoice/sales_invoice.py @@ -1,7 +1,6 @@ # Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors # License: GNU General Public License v3. See license.txt -from __future__ import unicode_literals import frappe from frappe import _, msgprint, throw @@ -19,7 +18,6 @@ from frappe.utils import ( getdate, nowdate, ) -from six import iteritems import erpnext from erpnext.accounts.deferred_revenue import validate_service_stop_date @@ -37,10 +35,9 @@ from erpnext.assets.doctype.asset.depreciation import ( get_disposal_account_and_cost_center, get_gl_entries_on_asset_disposal, get_gl_entries_on_asset_regain, - post_depreciation_entries, + make_depreciation_entry, ) from erpnext.controllers.selling_controller import SellingController -from erpnext.healthcare.utils import manage_invoice_submit_cancel from erpnext.projects.doctype.timesheet.timesheet import get_projectwise_timesheet_data from erpnext.setup.doctype.company.company import update_company_current_month_sales from erpnext.stock.doctype.batch.batch import set_batch_nos @@ -230,9 +227,6 @@ class SalesInvoice(SellingController): # this sequence because outstanding may get -ve self.make_gl_entries() - if self.update_stock == 1: - self.repost_future_sle_and_gle() - if self.update_stock == 1: self.repost_future_sle_and_gle() @@ -263,13 +257,6 @@ class SalesInvoice(SellingController): if self.redeem_loyalty_points and not self.is_consolidated and self.loyalty_points: self.apply_loyalty_points() - # Healthcare Service Invoice. - domain_settings = frappe.get_doc('Domain Settings') - active_domains = [d.domain for d in domain_settings.active_domains] - - if "Healthcare" in active_domains: - manage_invoice_submit_cancel(self, "on_submit") - self.process_common_party_accounting() def validate_pos_return(self): @@ -352,12 +339,6 @@ class SalesInvoice(SellingController): unlink_inter_company_doc(self.doctype, self.name, self.inter_company_invoice_reference) - # Healthcare Service Invoice. - domain_settings = frappe.get_doc('Domain Settings') - active_domains = [d.domain for d in domain_settings.active_domains] - - if "Healthcare" in active_domains: - manage_invoice_submit_cancel(self, "on_cancel") self.unlink_sales_invoice_from_timesheets() self.ignore_linked_doctypes = ('GL Entry', 'Stock Ledger Entry', 'Repost Item Valuation') @@ -499,7 +480,7 @@ class SalesInvoice(SellingController): self.account_for_change_amount = frappe.get_cached_value('Company', self.company, 'default_cash_account') from erpnext.stock.get_item_details import get_pos_profile, get_pos_profile_item_details - if not self.pos_profile: + if not self.pos_profile and not self.flags.ignore_pos_profile: pos_profile = get_pos_profile(self.company) or {} if not pos_profile: return @@ -551,7 +532,7 @@ class SalesInvoice(SellingController): for item in self.get("items"): if item.get('item_code'): profile_details = get_pos_profile_item_details(pos, frappe._dict(item.as_dict()), pos, update_data=True) - for fname, val in iteritems(profile_details): + for fname, val in profile_details.items(): if (not for_validate) or (for_validate and not item.get(fname)): item.set(fname, val) @@ -657,7 +638,7 @@ class SalesInvoice(SellingController): return prev_doc_field_map = {'Sales Order': ['so_required', 'is_pos'],'Delivery Note': ['dn_required', 'update_stock']} - for key, value in iteritems(prev_doc_field_map): + for key, value in prev_doc_field_map.items(): if frappe.db.get_single_value('Selling Settings', value[0]) == 'Yes': if frappe.get_value('Customer', self.customer, value[0]): @@ -772,7 +753,7 @@ class SalesInvoice(SellingController): if self.project: for data in get_projectwise_timesheet_data(self.project): self.append('timesheets', { - 'time_sheet': data.parent, + 'time_sheet': data.time_sheet, 'billing_hours': data.billing_hours, 'billing_amount': data.billing_amount, 'timesheet_detail': data.name, @@ -783,12 +764,11 @@ class SalesInvoice(SellingController): self.calculate_billing_amount_for_timesheet() def calculate_billing_amount_for_timesheet(self): - total_billing_amount = 0.0 - for data in self.timesheets: - if data.billing_amount: - total_billing_amount += data.billing_amount + def timesheet_sum(field): + return sum((ts.get(field) or 0.0) for ts in self.timesheets) - self.total_billing_amount = total_billing_amount + self.total_billing_amount = timesheet_sum("billing_amount") + self.total_billing_hours = timesheet_sum("billing_hours") def get_warehouse(self): user_pos_profile = frappe.db.sql("""select name, warehouse from `tabPOS Profile` @@ -952,6 +932,7 @@ class SalesInvoice(SellingController): asset.db_set("disposal_date", None) if asset.calculate_depreciation: + self.reverse_depreciation_entry_made_after_sale(asset) self.reset_depreciation_schedule(asset) else: @@ -1015,22 +996,20 @@ class SalesInvoice(SellingController): def depreciate_asset(self, asset): asset.flags.ignore_validate_update_after_submit = True - asset.prepare_depreciation_data(self.posting_date) + asset.prepare_depreciation_data(date_of_sale=self.posting_date) asset.save() - post_depreciation_entries(self.posting_date) + make_depreciation_entry(asset.name, self.posting_date) def reset_depreciation_schedule(self, asset): asset.flags.ignore_validate_update_after_submit = True # recreate original depreciation schedule of the asset - asset.prepare_depreciation_data() + asset.prepare_depreciation_data(date_of_return=self.posting_date) self.modify_depreciation_schedule_for_asset_repairs(asset) asset.save() - self.delete_depreciation_entry_made_after_sale(asset) - def modify_depreciation_schedule_for_asset_repairs(self, asset): asset_repairs = frappe.get_all( 'Asset Repair', @@ -1044,7 +1023,7 @@ class SalesInvoice(SellingController): asset_repair.modify_depreciation_schedule() asset.prepare_depreciation_data() - def delete_depreciation_entry_made_after_sale(self, asset): + def reverse_depreciation_entry_made_after_sale(self, asset): from erpnext.accounts.doctype.journal_entry.journal_entry import make_reverse_journal_entry posting_date_of_original_invoice = self.get_posting_date_of_sales_invoice() @@ -1059,11 +1038,19 @@ class SalesInvoice(SellingController): row += 1 if schedule.schedule_date == posting_date_of_original_invoice: - if not self.sale_was_made_on_original_schedule_date(asset, schedule, row, posting_date_of_original_invoice): + if not self.sale_was_made_on_original_schedule_date(asset, schedule, row, posting_date_of_original_invoice) \ + or self.sale_happens_in_the_future(posting_date_of_original_invoice): + reverse_journal_entry = make_reverse_journal_entry(schedule.journal_entry) reverse_journal_entry.posting_date = nowdate() + frappe.flags.is_reverse_depr_entry = True reverse_journal_entry.submit() + frappe.flags.is_reverse_depr_entry = False + asset.flags.ignore_validate_update_after_submit = True + schedule.journal_entry = None + asset.save() + def get_posting_date_of_sales_invoice(self): return frappe.db.get_value('Sales Invoice', self.return_against, 'posting_date') @@ -1078,6 +1065,12 @@ class SalesInvoice(SellingController): return True return False + def sale_happens_in_the_future(self, posting_date_of_original_invoice): + if posting_date_of_original_invoice > getdate(): + return True + + return False + @property def enable_discount_accounting(self): if not hasattr(self, "_enable_discount_accounting"): @@ -1302,12 +1295,20 @@ class SalesInvoice(SellingController): serial_nos = item.serial_no or "" si_serial_nos = set(get_serial_nos(serial_nos)) + serial_no_diff = si_serial_nos - dn_serial_nos - if si_serial_nos - dn_serial_nos: - frappe.throw(_("Serial Numbers in row {0} does not match with Delivery Note").format(item.idx)) + if serial_no_diff: + dn_link = frappe.utils.get_link_to_form("Delivery Note", item.delivery_note) + serial_no_msg = ", ".join(frappe.bold(d) for d in serial_no_diff) + + msg = _("Row #{0}: The following Serial Nos are not present in Delivery Note {1}:").format( + item.idx, dn_link) + msg += " " + serial_no_msg + + frappe.throw(msg=msg, title=_("Serial Nos Mismatch")) if item.serial_no and cint(item.qty) != len(si_serial_nos): - frappe.throw(_("Row {0}: {1} Serial numbers required for Item {2}. You have provided {3}.").format( + frappe.throw(_("Row #{0}: {1} Serial numbers required for Item {2}. You have provided {3}.").format( item.idx, item.qty, item.item_code, len(si_serial_nos))) def update_project(self): @@ -1430,59 +1431,14 @@ class SalesInvoice(SellingController): if points_to_redeem < 1: # since points_to_redeem is integer break - # Healthcare - @frappe.whitelist() - def set_healthcare_services(self, checked_values): - self.set("items", []) - from erpnext.stock.get_item_details import get_item_details - for checked_item in checked_values: - item_line = self.append("items", {}) - price_list, price_list_currency = frappe.db.get_values("Price List", {"selling": 1}, ['name', 'currency'])[0] - args = { - 'doctype': "Sales Invoice", - 'item_code': checked_item['item'], - 'company': self.company, - 'customer': frappe.db.get_value("Patient", self.patient, "customer"), - 'selling_price_list': price_list, - 'price_list_currency': price_list_currency, - 'plc_conversion_rate': 1.0, - 'conversion_rate': 1.0 - } - item_details = get_item_details(args) - item_line.item_code = checked_item['item'] - item_line.qty = 1 - if checked_item['qty']: - item_line.qty = checked_item['qty'] - if checked_item['rate']: - item_line.rate = checked_item['rate'] - else: - item_line.rate = item_details.price_list_rate - item_line.amount = float(item_line.rate) * float(item_line.qty) - if checked_item['income_account']: - item_line.income_account = checked_item['income_account'] - if checked_item['dt']: - item_line.reference_dt = checked_item['dt'] - if checked_item['dn']: - item_line.reference_dn = checked_item['dn'] - if checked_item['description']: - item_line.description = checked_item['description'] - - self.set_missing_values(for_validate = True) - def set_status(self, update=False, status=None, update_modified=True): if self.is_new(): if self.get('amended_from'): self.status = 'Draft' return - precision = self.precision("outstanding_amount") - outstanding_amount = flt(self.outstanding_amount, precision) - due_date = getdate(self.due_date) - nowdate = getdate() - - discounting_status = None - if self.is_discounted: - discounting_status = get_discounting_status(self.name) + outstanding_amount = flt(self.outstanding_amount, self.precision("outstanding_amount")) + total = get_total_in_party_account_currency(self) if not status: if self.docstatus == 2: @@ -1490,15 +1446,13 @@ class SalesInvoice(SellingController): elif self.docstatus == 1: if self.is_internal_transfer(): self.status = 'Internal Transfer' - elif outstanding_amount > 0 and due_date < nowdate and self.is_discounted and discounting_status=='Disbursed': - self.status = "Overdue and Discounted" - elif outstanding_amount > 0 and due_date < nowdate: + elif is_overdue(self, total): self.status = "Overdue" - elif outstanding_amount > 0 and due_date >= nowdate and self.is_discounted and discounting_status=='Disbursed': - self.status = "Unpaid and Discounted" - elif outstanding_amount > 0 and due_date >= nowdate: + elif 0 < outstanding_amount < total: + self.status = "Partly Paid" + elif outstanding_amount > 0 and getdate(self.due_date) >= getdate(): self.status = "Unpaid" - #Check if outstanding amount is 0 due to credit note issued against invoice + # Check if outstanding amount is 0 due to credit note issued against invoice elif outstanding_amount <= 0 and self.is_return == 0 and frappe.db.get_value('Sales Invoice', {'is_return': 1, 'return_against': self.name, 'docstatus': 1}): self.status = "Credit Note Issued" elif self.is_return == 1: @@ -1507,12 +1461,57 @@ class SalesInvoice(SellingController): self.status = "Paid" else: self.status = "Submitted" + + if ( + self.status in ("Unpaid", "Partly Paid", "Overdue") + and self.is_discounted + and get_discounting_status(self.name) == "Disbursed" + ): + self.status += " and Discounted" + else: self.status = "Draft" if update: self.db_set('status', self.status, update_modified = update_modified) + +def get_total_in_party_account_currency(doc): + total_fieldname = ( + "grand_total" + if doc.disable_rounded_total + else "rounded_total" + ) + if doc.party_account_currency != doc.currency: + total_fieldname = "base_" + total_fieldname + + return flt(doc.get(total_fieldname), doc.precision(total_fieldname)) + +def is_overdue(doc, total): + outstanding_amount = flt(doc.outstanding_amount, doc.precision("outstanding_amount")) + if outstanding_amount <= 0: + return + + today = getdate() + if doc.get('is_pos') or not doc.get('payment_schedule'): + return getdate(doc.due_date) < today + + # calculate payable amount till date + payment_amount_field = ( + "base_payment_amount" + if doc.party_account_currency != doc.currency + else "payment_amount" + ) + + payable_amount = sum( + payment.get(payment_amount_field) + for payment in doc.payment_schedule + if getdate(payment.due_date) < today + ) + + return (total - outstanding_amount) < payable_amount + + def get_discounting_status(sales_invoice): status = None @@ -1987,22 +1986,23 @@ def update_multi_mode_option(doc, pos_profile): def append_payment(payment_mode): payment = doc.append('payments', {}) payment.default = payment_mode.default - payment.mode_of_payment = payment_mode.parent + payment.mode_of_payment = payment_mode.mop payment.account = payment_mode.default_account payment.type = payment_mode.type doc.set('payments', []) invalid_modes = [] - for pos_payment_method in pos_profile.get('payments'): - pos_payment_method = pos_payment_method.as_dict() + mode_of_payments = [d.mode_of_payment for d in pos_profile.get('payments')] + mode_of_payments_info = get_mode_of_payments_info(mode_of_payments, doc.company) - payment_mode = get_mode_of_payment_info(pos_payment_method.mode_of_payment, doc.company) + for row in pos_profile.get('payments'): + payment_mode = mode_of_payments_info.get(row.mode_of_payment) if not payment_mode: - invalid_modes.append(get_link_to_form("Mode of Payment", pos_payment_method.mode_of_payment)) + invalid_modes.append(get_link_to_form("Mode of Payment", row.mode_of_payment)) continue - payment_mode[0].default = pos_payment_method.default - append_payment(payment_mode[0]) + payment_mode.default = row.default + append_payment(payment_mode) if invalid_modes: if invalid_modes == 1: @@ -2018,6 +2018,24 @@ def get_all_mode_of_payments(doc): where mpa.parent = mp.name and mpa.company = %(company)s and mp.enabled = 1""", {'company': doc.company}, as_dict=1) +def get_mode_of_payments_info(mode_of_payments, company): + data = frappe.db.sql( + """ + select + mpa.default_account, mpa.parent as mop, mp.type as type + from + `tabMode of Payment Account` mpa,`tabMode of Payment` mp + where + mpa.parent = mp.name and + mpa.company = %s and + mp.enabled = 1 and + mp.name in %s + group by + mp.name + """, (company, mode_of_payments), as_dict=1) + + return {row.get('mop'): row for row in data} + def get_mode_of_payment_info(mode_of_payment, company): return frappe.db.sql(""" select mpa.default_account, mpa.parent, mp.type as type diff --git a/erpnext/accounts/doctype/sales_invoice/sales_invoice_dashboard.py b/erpnext/accounts/doctype/sales_invoice/sales_invoice_dashboard.py index 64b35b2987e..5cdc8dae25f 100644 --- a/erpnext/accounts/doctype/sales_invoice/sales_invoice_dashboard.py +++ b/erpnext/accounts/doctype/sales_invoice/sales_invoice_dashboard.py @@ -1,5 +1,3 @@ -from __future__ import unicode_literals - from frappe import _ diff --git a/erpnext/accounts/doctype/sales_invoice/sales_invoice_list.js b/erpnext/accounts/doctype/sales_invoice/sales_invoice_list.js index 1a01cb58f2a..06e6f511839 100644 --- a/erpnext/accounts/doctype/sales_invoice/sales_invoice_list.js +++ b/erpnext/accounts/doctype/sales_invoice/sales_invoice_list.js @@ -6,18 +6,20 @@ frappe.listview_settings['Sales Invoice'] = { add_fields: ["customer", "customer_name", "base_grand_total", "outstanding_amount", "due_date", "company", "currency", "is_return"], get_indicator: function(doc) { - var status_color = { + const status_colors = { "Draft": "grey", "Unpaid": "orange", "Paid": "green", "Return": "gray", "Credit Note Issued": "gray", "Unpaid and Discounted": "orange", + "Partly Paid and Discounted": "yellow", "Overdue and Discounted": "red", "Overdue": "red", + "Partly Paid": "yellow", "Internal Transfer": "darkgrey" }; - return [__(doc.status), status_color[doc.status], "status,=,"+doc.status]; + return [__(doc.status), status_colors[doc.status], "status,=,"+doc.status]; }, right_column: "grand_total" }; diff --git a/erpnext/accounts/doctype/sales_invoice/test_sales_invoice.py b/erpnext/accounts/doctype/sales_invoice/test_sales_invoice.py index da0c3151933..b5453ac56eb 100644 --- a/erpnext/accounts/doctype/sales_invoice/test_sales_invoice.py +++ b/erpnext/accounts/doctype/sales_invoice/test_sales_invoice.py @@ -1,6 +1,5 @@ # Copyright (c) 2018, Frappe Technologies Pvt. Ltd. and Contributors # License: GNU General Public License v3. See license.txt -from __future__ import unicode_literals import copy import unittest @@ -9,7 +8,6 @@ import frappe from frappe.model.dynamic_links import get_dynamic_link_map from frappe.model.naming import make_autoname from frappe.utils import add_days, flt, getdate, nowdate -from six import iteritems import erpnext from erpnext.accounts.doctype.account.test_account import create_account, get_inventory_account @@ -133,6 +131,7 @@ class TestSalesInvoice(unittest.TestCase): def test_payment_entry_unlink_against_invoice(self): from erpnext.accounts.doctype.payment_entry.test_payment_entry import get_payment_entry + si = frappe.copy_doc(test_records[0]) si.is_pos = 0 si.insert() @@ -156,6 +155,7 @@ class TestSalesInvoice(unittest.TestCase): def test_payment_entry_unlink_against_standalone_credit_note(self): from erpnext.accounts.doctype.payment_entry.test_payment_entry import get_payment_entry + si1 = create_sales_invoice(rate=1000) si2 = create_sales_invoice(rate=300) si3 = create_sales_invoice(qty=-1, rate=300, is_return=1) @@ -344,7 +344,7 @@ class TestSalesInvoice(unittest.TestCase): # check if item values are calculated for i, d in enumerate(si.get("items")): - for k, v in iteritems(expected_values[i]): + for k, v in expected_values[i].items(): self.assertEqual(d.get(k), v) # check net total @@ -647,7 +647,7 @@ class TestSalesInvoice(unittest.TestCase): # check if item values are calculated for i, d in enumerate(si.get("items")): - for key, val in iteritems(expected_values[i]): + for key, val in expected_values[i].items(): self.assertEqual(d.get(key), val) # check net total @@ -1085,8 +1085,6 @@ class TestSalesInvoice(unittest.TestCase): actual_qty_1 = get_qty_after_transaction(item_code = "_Test Item", warehouse = "Stores - TCP1") - frappe.db.commit() - self.assertEqual(actual_qty_0 - 5, actual_qty_1) # outgoing_rate @@ -1420,15 +1418,22 @@ class TestSalesInvoice(unittest.TestCase): itemised_tax, itemised_taxable_amount = get_itemised_tax_breakup_data(si) expected_itemised_tax = { - "999800": { + "_Test Item": { "Service Tax": { "tax_rate": 10.0, - "tax_amount": 1500.0 + "tax_amount": 1000.0 + } + }, + "_Test Item 2": { + "Service Tax": { + "tax_rate": 10.0, + "tax_amount": 500.0 } } } expected_itemised_taxable_amount = { - "999800": 15000.0 + "_Test Item": 10000.0, + "_Test Item 2": 5000.0 } self.assertEqual(itemised_tax, expected_itemised_tax) @@ -1598,28 +1603,12 @@ class TestSalesInvoice(unittest.TestCase): si.shipping_rule = shipping_rule.name si.insert() - - shipping_amount = 0.0 - for condition in shipping_rule.get("conditions"): - if not condition.to_value or (flt(condition.from_value) <= si.net_total <= flt(condition.to_value)): - shipping_amount = condition.shipping_amount - - shipping_charge = { - "doctype": "Sales Taxes and Charges", - "category": "Valuation and Total", - "charge_type": "Actual", - "account_head": shipping_rule.account, - "cost_center": shipping_rule.cost_center, - "tax_amount": shipping_amount, - "description": shipping_rule.name - } - si.append("taxes", shipping_charge) si.save() self.assertEqual(si.net_total, 1250) - self.assertEqual(si.total_taxes_and_charges, 577.05) - self.assertEqual(si.grand_total, 1827.05) + self.assertEqual(si.total_taxes_and_charges, 468.85) + self.assertEqual(si.grand_total, 1718.85) @@ -1639,6 +1628,7 @@ class TestSalesInvoice(unittest.TestCase): def test_credit_note(self): from erpnext.accounts.doctype.payment_entry.test_payment_entry import get_payment_entry + si = create_sales_invoice(item_code = "_Test Item", qty = (5 * -1), rate=500, is_return = 1) outstanding_amount = get_outstanding_amount(si.doctype, @@ -1790,6 +1780,47 @@ class TestSalesInvoice(unittest.TestCase): check_gl_entries(self, si.name, expected_gle, "2019-01-30") + def test_deferred_revenue_post_account_freeze_upto_by_admin(self): + frappe.set_user("Administrator") + + frappe.db.set_value('Accounts Settings', None, 'acc_frozen_upto', None) + frappe.db.set_value('Accounts Settings', None, 'frozen_accounts_modifier', None) + + deferred_account = create_account(account_name="Deferred Revenue", + parent_account="Current Liabilities - _TC", company="_Test Company") + + item = create_item("_Test Item for Deferred Accounting") + item.enable_deferred_revenue = 1 + item.deferred_revenue_account = deferred_account + item.no_of_months = 12 + item.save() + + si = create_sales_invoice(item=item.name, posting_date="2019-01-10", do_not_save=True) + si.items[0].enable_deferred_revenue = 1 + si.items[0].service_start_date = "2019-01-10" + si.items[0].service_end_date = "2019-03-15" + si.items[0].deferred_revenue_account = deferred_account + si.save() + si.submit() + + frappe.db.set_value('Accounts Settings', None, 'acc_frozen_upto', getdate('2019-01-31')) + frappe.db.set_value('Accounts Settings', None, 'frozen_accounts_modifier', 'System Manager') + + pda1 = frappe.get_doc(dict( + doctype='Process Deferred Accounting', + posting_date=nowdate(), + start_date="2019-01-01", + end_date="2019-03-31", + type="Income", + company="_Test Company" + )) + + pda1.insert() + self.assertRaises(frappe.ValidationError, pda1.submit) + + frappe.db.set_value('Accounts Settings', None, 'acc_frozen_upto', None) + frappe.db.set_value('Accounts Settings', None, 'frozen_accounts_modifier', None) + def test_fixed_deferred_revenue(self): deferred_account = create_account(account_name="Deferred Revenue", parent_account="Current Liabilities - _TC", company="_Test Company") @@ -1972,11 +2003,7 @@ class TestSalesInvoice(unittest.TestCase): frappe.local.enable_perpetual_inventory['_Test Company 1'] = old_perpetual_inventory frappe.db.set_value("Stock Settings", None, "allow_negative_stock", old_negative_stock) - def test_sle_if_target_warehouse_exists_accidentally(self): - """ - Check if inward entry exists if Target Warehouse accidentally exists - but Customer is not an internal customer. - """ + def test_sle_for_target_warehouse(self): se = make_stock_entry( item_code="138-CMS Shoe", target="Finished Goods - _TC", @@ -1997,9 +2024,9 @@ class TestSalesInvoice(unittest.TestCase): sles = frappe.get_all("Stock Ledger Entry", filters={"voucher_no": si.name}, fields=["name", "actual_qty"]) - # check if only one SLE for outward entry is created - self.assertEqual(len(sles), 1) - self.assertEqual(sles[0].actual_qty, -1) + # check if both SLEs are created + self.assertEqual(len(sles), 2) + self.assertEqual(sum(d.actual_qty for d in sles), 0.0) # tear down si.cancel() @@ -2192,9 +2219,9 @@ class TestSalesInvoice(unittest.TestCase): check_gl_entries(self, si.name, expected_gle, add_days(nowdate(), -1)) enable_discount_accounting(enable=0) - def test_asset_depreciation_on_sale(self): + def test_asset_depreciation_on_sale_with_pro_rata(self): """ - Tests if an Asset set to depreciate yearly on June 30, that gets sold on Sept 30, creates an additional depreciation entry on Sept 30. + Tests if an Asset set to depreciate yearly on June 30, that gets sold on Sept 30, creates an additional depreciation entry on its date of sale. """ create_asset_data() @@ -2207,7 +2234,7 @@ class TestSalesInvoice(unittest.TestCase): expected_values = [ ["2020-06-30", 1311.48, 1311.48], ["2021-06-30", 20000.0, 21311.48], - ["2021-09-30", 3966.76, 25278.24] + ["2021-09-30", 5041.1, 26352.58] ] for i, schedule in enumerate(asset.schedules): @@ -2216,10 +2243,64 @@ class TestSalesInvoice(unittest.TestCase): self.assertEqual(expected_values[i][2], schedule.accumulated_depreciation_amount) self.assertTrue(schedule.journal_entry) + def test_asset_depreciation_on_sale_without_pro_rata(self): + """ + Tests if an Asset set to depreciate yearly on Dec 31, that gets sold on Dec 31 after two years, created an additional depreciation entry on its date of sale. + """ + + create_asset_data() + asset = create_asset(item_code="Macbook Pro", calculate_depreciation=1, + available_for_use_date=getdate("2019-12-31"), total_number_of_depreciations=3, + expected_value_after_useful_life=10000, depreciation_start_date=getdate("2020-12-31"), submit=1) + + post_depreciation_entries(getdate("2021-09-30")) + + create_sales_invoice(item_code="Macbook Pro", asset=asset.name, qty=1, rate=90000, posting_date=getdate("2021-12-31")) + asset.load_from_db() + + expected_values = [ + ["2020-12-31", 30000, 30000], + ["2021-12-31", 30000, 60000] + ] + + for i, schedule in enumerate(asset.schedules): + self.assertEqual(getdate(expected_values[i][0]), schedule.schedule_date) + self.assertEqual(expected_values[i][1], schedule.depreciation_amount) + self.assertEqual(expected_values[i][2], schedule.accumulated_depreciation_amount) + self.assertTrue(schedule.journal_entry) + + def test_depreciation_on_return_of_sold_asset(self): + from erpnext.controllers.sales_and_purchase_return import make_return_doc + + create_asset_data() + asset = create_asset(item_code="Macbook Pro", calculate_depreciation=1, submit=1) + post_depreciation_entries(getdate("2021-09-30")) + + si = create_sales_invoice(item_code="Macbook Pro", asset=asset.name, qty=1, rate=90000, posting_date=getdate("2021-09-30")) + return_si = make_return_doc("Sales Invoice", si.name) + return_si.submit() + asset.load_from_db() + + expected_values = [ + ["2020-06-30", 1311.48, 1311.48, True], + ["2021-06-30", 20000.0, 21311.48, True], + ["2022-06-30", 20000.0, 41311.48, False], + ["2023-06-30", 20000.0, 61311.48, False], + ["2024-06-30", 20000.0, 81311.48, False], + ["2025-06-06", 18688.52, 100000.0, False] + ] + + for i, schedule in enumerate(asset.schedules): + self.assertEqual(getdate(expected_values[i][0]), schedule.schedule_date) + self.assertEqual(expected_values[i][1], schedule.depreciation_amount) + self.assertEqual(expected_values[i][2], schedule.accumulated_depreciation_amount) + self.assertEqual(schedule.journal_entry, schedule.journal_entry) + def test_sales_invoice_against_supplier(self): from erpnext.accounts.doctype.opening_invoice_creation_tool.test_opening_invoice_creation_tool import ( make_customer, ) + from erpnext.accounts.doctype.party_link.party_link import create_party_link from erpnext.buying.doctype.supplier.test_supplier import create_supplier # create a customer @@ -2228,13 +2309,7 @@ class TestSalesInvoice(unittest.TestCase): supplier = create_supplier(supplier_name="_Test Common Supplier").name # create a party link between customer & supplier - # set primary role as supplier - party_link = frappe.new_doc("Party Link") - party_link.primary_role = "Supplier" - party_link.primary_party = supplier - party_link.secondary_role = "Customer" - party_link.secondary_party = customer - party_link.save() + party_link = create_party_link("Supplier", supplier, customer) # enable common party accounting frappe.db.set_value('Accounts Settings', None, 'enable_common_party_accounting', 1) @@ -2262,6 +2337,66 @@ class TestSalesInvoice(unittest.TestCase): party_link.delete() frappe.db.set_value('Accounts Settings', None, 'enable_common_party_accounting', 0) + def test_payment_statuses(self): + from erpnext.accounts.doctype.payment_entry.test_payment_entry import get_payment_entry + + today = nowdate() + + # Test Overdue + si = create_sales_invoice(do_not_submit=True) + si.payment_schedule = [] + si.append("payment_schedule", { + "due_date": add_days(today, -5), + "invoice_portion": 50, + "payment_amount": si.grand_total / 2 + }) + si.append("payment_schedule", { + "due_date": add_days(today, 5), + "invoice_portion": 50, + "payment_amount": si.grand_total / 2 + }) + si.submit() + self.assertEqual(si.status, "Overdue") + + # Test payment less than due amount + pe = get_payment_entry("Sales Invoice", si.name, bank_account="_Test Bank - _TC") + pe.reference_no = "1" + pe.reference_date = nowdate() + pe.paid_amount = 1 + pe.references[0].allocated_amount = pe.paid_amount + pe.submit() + si.reload() + self.assertEqual(si.status, "Overdue") + + # Test Partly Paid + pe = frappe.copy_doc(pe) + pe.paid_amount = si.grand_total / 2 + pe.references[0].allocated_amount = pe.paid_amount + pe.submit() + si.reload() + self.assertEqual(si.status, "Partly Paid") + + # Test Paid + pe = get_payment_entry("Sales Invoice", si.name, bank_account="_Test Bank - _TC") + pe.reference_no = "1" + pe.reference_date = nowdate() + pe.paid_amount = si.outstanding_amount + pe.submit() + si.reload() + self.assertEqual(si.status, "Paid") + + def test_sales_invoice_submission_post_account_freezing_date(self): + frappe.db.set_value('Accounts Settings', None, 'acc_frozen_upto', add_days(getdate(), 1)) + si = create_sales_invoice(do_not_save=True) + si.posting_date = add_days(getdate(), 1) + si.save() + + self.assertRaises(frappe.ValidationError, si.submit) + si.posting_date = getdate() + si.submit() + + frappe.db.set_value('Accounts Settings', None, 'acc_frozen_upto', None) + def get_sales_invoice_for_e_invoice(): si = make_sales_invoice_for_ewaybill() si.naming_series = 'INV-2020-.#####' @@ -2294,6 +2429,7 @@ def make_test_address_for_ewaybill(): if not frappe.db.exists('Address', '_Test Address for Eway bill-Billing'): address = frappe.get_doc({ "address_line1": "_Test Address Line 1", + "address_line2": "_Test Address Line 2", "address_title": "_Test Address for Eway bill", "address_type": "Billing", "city": "_Test City", @@ -2315,11 +2451,12 @@ def make_test_address_for_ewaybill(): address.save() - if not frappe.db.exists('Address', '_Test Customer-Address for Eway bill-Shipping'): + if not frappe.db.exists('Address', '_Test Customer-Address for Eway bill-Billing'): address = frappe.get_doc({ "address_line1": "_Test Address Line 1", + "address_line2": "_Test Address Line 2", "address_title": "_Test Customer-Address for Eway bill", - "address_type": "Shipping", + "address_type": "Billing", "city": "_Test City", "state": "Test State", "country": "India", @@ -2339,9 +2476,34 @@ def make_test_address_for_ewaybill(): address.save() + if not frappe.db.exists('Address', '_Test Customer-Address for Eway bill-Shipping'): + address = frappe.get_doc({ + "address_line1": "_Test Address Line 1", + "address_line2": "_Test Address Line 2", + "address_title": "_Test Customer-Address for Eway bill", + "address_type": "Shipping", + "city": "_Test City", + "state": "Test State", + "country": "India", + "doctype": "Address", + "is_primary_address": 1, + "phone": "+910000000000", + "gst_state": "Maharashtra", + "gst_state_number": "27", + "pincode": "410098" + }).insert() + + address.append("links", { + "link_doctype": "Customer", + "link_name": "_Test Customer" + }) + + address.save() + if not frappe.db.exists('Address', '_Test Dispatch-Address for Eway bill-Shipping'): address = frappe.get_doc({ "address_line1": "_Test Dispatch Address Line 1", + "address_line2": "_Test Dispatch Address Line 2", "address_title": "_Test Dispatch-Address for Eway bill", "address_type": "Shipping", "city": "_Test City", @@ -2356,11 +2518,6 @@ def make_test_address_for_ewaybill(): "pincode": "1100101" }).insert() - address.append("links", { - "link_doctype": "Company", - "link_name": "_Test Company" - }) - address.save() def make_test_transporter_for_ewaybill(): @@ -2400,7 +2557,8 @@ def make_sales_invoice_for_ewaybill(): si.distance = 2000 si.company_address = "_Test Address for Eway bill-Billing" - si.customer_address = "_Test Customer-Address for Eway bill-Shipping" + si.customer_address = "_Test Customer-Address for Eway bill-Billing" + si.shipping_address_name = "_Test Customer-Address for Eway bill-Shipping" si.dispatch_address_name = "_Test Dispatch-Address for Eway bill-Shipping" si.vehicle_no = "KA12KA1234" si.gst_category = "Registered Regular" diff --git a/erpnext/accounts/doctype/sales_invoice_advance/__init__.py b/erpnext/accounts/doctype/sales_invoice_advance/__init__.py index baffc488252..e69de29bb2d 100644 --- a/erpnext/accounts/doctype/sales_invoice_advance/__init__.py +++ b/erpnext/accounts/doctype/sales_invoice_advance/__init__.py @@ -1 +0,0 @@ -from __future__ import unicode_literals diff --git a/erpnext/accounts/doctype/sales_invoice_advance/sales_invoice_advance.json b/erpnext/accounts/doctype/sales_invoice_advance/sales_invoice_advance.json index 29422d68cf6..f92b57a45e1 100644 --- a/erpnext/accounts/doctype/sales_invoice_advance/sales_invoice_advance.json +++ b/erpnext/accounts/doctype/sales_invoice_advance/sales_invoice_advance.json @@ -98,6 +98,7 @@ "width": "120px" }, { + "depends_on": "exchange_gain_loss", "fieldname": "exchange_gain_loss", "fieldtype": "Currency", "label": "Exchange Gain/Loss", @@ -105,6 +106,7 @@ "read_only": 1 }, { + "depends_on": "exchange_gain_loss", "fieldname": "ref_exchange_rate", "fieldtype": "Float", "label": "Reference Exchange Rate", @@ -116,7 +118,7 @@ "index_web_pages_for_search": 1, "istable": 1, "links": [], - "modified": "2021-06-04 20:25:49.832052", + "modified": "2021-09-26 15:47:46.911595", "modified_by": "Administrator", "module": "Accounts", "name": "Sales Invoice Advance", diff --git a/erpnext/accounts/doctype/sales_invoice_advance/sales_invoice_advance.py b/erpnext/accounts/doctype/sales_invoice_advance/sales_invoice_advance.py index ae69598a66a..6d4bd4633c3 100644 --- a/erpnext/accounts/doctype/sales_invoice_advance/sales_invoice_advance.py +++ b/erpnext/accounts/doctype/sales_invoice_advance/sales_invoice_advance.py @@ -1,7 +1,6 @@ # Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors # License: GNU General Public License v3. See license.txt -from __future__ import unicode_literals from frappe.model.document import Document diff --git a/erpnext/accounts/doctype/sales_invoice_item/__init__.py b/erpnext/accounts/doctype/sales_invoice_item/__init__.py index baffc488252..e69de29bb2d 100644 --- a/erpnext/accounts/doctype/sales_invoice_item/__init__.py +++ b/erpnext/accounts/doctype/sales_invoice_item/__init__.py @@ -1 +0,0 @@ -from __future__ import unicode_literals diff --git a/erpnext/accounts/doctype/sales_invoice_item/sales_invoice_item.py b/erpnext/accounts/doctype/sales_invoice_item/sales_invoice_item.py index 063c591f768..ebeaf8b5ef8 100644 --- a/erpnext/accounts/doctype/sales_invoice_item/sales_invoice_item.py +++ b/erpnext/accounts/doctype/sales_invoice_item/sales_invoice_item.py @@ -1,7 +1,6 @@ # Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors # License: GNU General Public License v3. See license.txt -from __future__ import unicode_literals from frappe.model.document import Document diff --git a/erpnext/accounts/doctype/sales_invoice_payment/sales_invoice_payment.py b/erpnext/accounts/doctype/sales_invoice_payment/sales_invoice_payment.py index a980ece580b..d9b1dbe346a 100644 --- a/erpnext/accounts/doctype/sales_invoice_payment/sales_invoice_payment.py +++ b/erpnext/accounts/doctype/sales_invoice_payment/sales_invoice_payment.py @@ -1,8 +1,6 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and contributors # For license information, please see license.txt -from __future__ import unicode_literals from frappe.model.document import Document diff --git a/erpnext/accounts/doctype/sales_invoice_timesheet/sales_invoice_timesheet.json b/erpnext/accounts/doctype/sales_invoice_timesheet/sales_invoice_timesheet.json index c90297328ee..69b7c129f09 100644 --- a/erpnext/accounts/doctype/sales_invoice_timesheet/sales_invoice_timesheet.json +++ b/erpnext/accounts/doctype/sales_invoice_timesheet/sales_invoice_timesheet.json @@ -7,12 +7,19 @@ "field_order": [ "activity_type", "description", - "billing_hours", - "billing_amount", + "section_break_3", + "from_time", "column_break_5", + "to_time", + "section_break_7", + "billing_hours", + "column_break_9", + "billing_amount", + "section_break_11", "time_sheet", - "project_name", - "timesheet_detail" + "timesheet_detail", + "column_break_13", + "project_name" ], "fields": [ { @@ -64,20 +71,53 @@ "label": "Description", "read_only": 1 }, + { + "fieldname": "from_time", + "fieldtype": "Datetime", + "label": "From Time" + }, + { + "fieldname": "to_time", + "fieldtype": "Datetime", + "label": "To Time" + }, + { + "fieldname": "section_break_3", + "fieldtype": "Section Break", + "label": "Time" + }, { "fieldname": "column_break_5", "fieldtype": "Column Break" }, + { + "fieldname": "section_break_7", + "fieldtype": "Section Break", + "label": "Totals" + }, + { + "fieldname": "column_break_9", + "fieldtype": "Column Break" + }, + { + "fieldname": "section_break_11", + "fieldtype": "Section Break", + "label": "Reference" + }, { "fieldname": "project_name", "fieldtype": "Data", "label": "Project Name", "read_only": 1 + }, + { + "fieldname": "column_break_13", + "fieldtype": "Column Break" } ], "istable": 1, "links": [], - "modified": "2021-06-08 14:43:02.748981", + "modified": "2021-10-02 03:48:44.979777", "modified_by": "Administrator", "module": "Accounts", "name": "Sales Invoice Timesheet", diff --git a/erpnext/accounts/doctype/sales_invoice_timesheet/sales_invoice_timesheet.py b/erpnext/accounts/doctype/sales_invoice_timesheet/sales_invoice_timesheet.py index e8d4b114fef..e50b1c28614 100644 --- a/erpnext/accounts/doctype/sales_invoice_timesheet/sales_invoice_timesheet.py +++ b/erpnext/accounts/doctype/sales_invoice_timesheet/sales_invoice_timesheet.py @@ -1,8 +1,6 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and contributors # For license information, please see license.txt -from __future__ import unicode_literals from frappe.model.document import Document diff --git a/erpnext/accounts/doctype/sales_taxes_and_charges/__init__.py b/erpnext/accounts/doctype/sales_taxes_and_charges/__init__.py index baffc488252..e69de29bb2d 100644 --- a/erpnext/accounts/doctype/sales_taxes_and_charges/__init__.py +++ b/erpnext/accounts/doctype/sales_taxes_and_charges/__init__.py @@ -1 +0,0 @@ -from __future__ import unicode_literals diff --git a/erpnext/accounts/doctype/sales_taxes_and_charges/sales_taxes_and_charges.py b/erpnext/accounts/doctype/sales_taxes_and_charges/sales_taxes_and_charges.py index 39872f33770..d412c1b7309 100644 --- a/erpnext/accounts/doctype/sales_taxes_and_charges/sales_taxes_and_charges.py +++ b/erpnext/accounts/doctype/sales_taxes_and_charges/sales_taxes_and_charges.py @@ -1,7 +1,6 @@ # Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors # License: GNU General Public License v3. See license.txt -from __future__ import unicode_literals from frappe.model.document import Document diff --git a/erpnext/accounts/doctype/sales_taxes_and_charges_template/sales_taxes_and_charges_template.py b/erpnext/accounts/doctype/sales_taxes_and_charges_template/sales_taxes_and_charges_template.py index 0a0bb3e00b9..b5909447dc8 100644 --- a/erpnext/accounts/doctype/sales_taxes_and_charges_template/sales_taxes_and_charges_template.py +++ b/erpnext/accounts/doctype/sales_taxes_and_charges_template/sales_taxes_and_charges_template.py @@ -1,7 +1,6 @@ # Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors # License: GNU General Public License v3. See license.txt -from __future__ import unicode_literals import frappe from frappe import _ diff --git a/erpnext/accounts/doctype/sales_taxes_and_charges_template/sales_taxes_and_charges_template_dashboard.py b/erpnext/accounts/doctype/sales_taxes_and_charges_template/sales_taxes_and_charges_template_dashboard.py index 522e282a170..bc1fd8ec32f 100644 --- a/erpnext/accounts/doctype/sales_taxes_and_charges_template/sales_taxes_and_charges_template_dashboard.py +++ b/erpnext/accounts/doctype/sales_taxes_and_charges_template/sales_taxes_and_charges_template_dashboard.py @@ -1,5 +1,3 @@ -from __future__ import unicode_literals - from frappe import _ diff --git a/erpnext/accounts/doctype/sales_taxes_and_charges_template/test_sales_taxes_and_charges_template.py b/erpnext/accounts/doctype/sales_taxes_and_charges_template/test_sales_taxes_and_charges_template.py index 1cad4129f83..7b13c6c6925 100644 --- a/erpnext/accounts/doctype/sales_taxes_and_charges_template/test_sales_taxes_and_charges_template.py +++ b/erpnext/accounts/doctype/sales_taxes_and_charges_template/test_sales_taxes_and_charges_template.py @@ -1,7 +1,5 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors and Contributors # See license.txt -from __future__ import unicode_literals import unittest diff --git a/erpnext/accounts/doctype/share_balance/share_balance.py b/erpnext/accounts/doctype/share_balance/share_balance.py index 0353e998237..4c9ec439eed 100644 --- a/erpnext/accounts/doctype/share_balance/share_balance.py +++ b/erpnext/accounts/doctype/share_balance/share_balance.py @@ -1,8 +1,6 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2018, Frappe Technologies Pvt. Ltd. and contributors # For license information, please see license.txt -from __future__ import unicode_literals from frappe.model.document import Document diff --git a/erpnext/accounts/doctype/share_transfer/share_transfer.py b/erpnext/accounts/doctype/share_transfer/share_transfer.py index 5117ef8b5b5..b543ad8204d 100644 --- a/erpnext/accounts/doctype/share_transfer/share_transfer.py +++ b/erpnext/accounts/doctype/share_transfer/share_transfer.py @@ -1,8 +1,6 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2017, Frappe Technologies Pvt. Ltd. and contributors # For license information, please see license.txt -from __future__ import unicode_literals import frappe from frappe import _ diff --git a/erpnext/accounts/doctype/share_transfer/test_share_transfer.py b/erpnext/accounts/doctype/share_transfer/test_share_transfer.py index b40e5fbbf8e..bc3a52167db 100644 --- a/erpnext/accounts/doctype/share_transfer/test_share_transfer.py +++ b/erpnext/accounts/doctype/share_transfer/test_share_transfer.py @@ -1,7 +1,5 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2017, Frappe Technologies Pvt. Ltd. and Contributors # See license.txt -from __future__ import unicode_literals import unittest diff --git a/erpnext/accounts/doctype/share_type/share_type.py b/erpnext/accounts/doctype/share_type/share_type.py index 5b133aa34ab..80365aa2f21 100644 --- a/erpnext/accounts/doctype/share_type/share_type.py +++ b/erpnext/accounts/doctype/share_type/share_type.py @@ -1,8 +1,6 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2017, Frappe Technologies Pvt. Ltd. and contributors # For license information, please see license.txt -from __future__ import unicode_literals from frappe.model.document import Document diff --git a/erpnext/accounts/doctype/share_type/share_type_dashboard.py b/erpnext/accounts/doctype/share_type/share_type_dashboard.py index 455b022577a..d5551d12471 100644 --- a/erpnext/accounts/doctype/share_type/share_type_dashboard.py +++ b/erpnext/accounts/doctype/share_type/share_type_dashboard.py @@ -1,5 +1,3 @@ -from __future__ import unicode_literals - from frappe import _ diff --git a/erpnext/accounts/doctype/share_type/test_share_type.py b/erpnext/accounts/doctype/share_type/test_share_type.py index a6f8d611c1b..b911c98388c 100644 --- a/erpnext/accounts/doctype/share_type/test_share_type.py +++ b/erpnext/accounts/doctype/share_type/test_share_type.py @@ -1,7 +1,5 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2017, Frappe Technologies Pvt. Ltd. and Contributors # See license.txt -from __future__ import unicode_literals import unittest diff --git a/erpnext/accounts/doctype/shareholder/shareholder.py b/erpnext/accounts/doctype/shareholder/shareholder.py index 12c50c8283b..8a0fa85a692 100644 --- a/erpnext/accounts/doctype/shareholder/shareholder.py +++ b/erpnext/accounts/doctype/shareholder/shareholder.py @@ -1,8 +1,6 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2017, Frappe Technologies Pvt. Ltd. and contributors # For license information, please see license.txt -from __future__ import unicode_literals from frappe.contacts.address_and_contact import ( delete_contact_and_address, diff --git a/erpnext/accounts/doctype/shareholder/shareholder_dashboard.py b/erpnext/accounts/doctype/shareholder/shareholder_dashboard.py index 0084f2567ab..c01ac23f1ee 100644 --- a/erpnext/accounts/doctype/shareholder/shareholder_dashboard.py +++ b/erpnext/accounts/doctype/shareholder/shareholder_dashboard.py @@ -1,6 +1,3 @@ -from __future__ import unicode_literals - - def get_data(): return { 'fieldname': 'shareholder', diff --git a/erpnext/accounts/doctype/shareholder/test_shareholder.py b/erpnext/accounts/doctype/shareholder/test_shareholder.py index 6790fdd2ff7..376ea711526 100644 --- a/erpnext/accounts/doctype/shareholder/test_shareholder.py +++ b/erpnext/accounts/doctype/shareholder/test_shareholder.py @@ -1,7 +1,5 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2017, Frappe Technologies Pvt. Ltd. and Contributors # See license.txt -from __future__ import unicode_literals import unittest diff --git a/erpnext/accounts/doctype/shipping_rule/shipping_rule.py b/erpnext/accounts/doctype/shipping_rule/shipping_rule.py index 28521014720..7e5129911e4 100644 --- a/erpnext/accounts/doctype/shipping_rule/shipping_rule.py +++ b/erpnext/accounts/doctype/shipping_rule/shipping_rule.py @@ -3,7 +3,6 @@ # For license information, please see license.txt -from __future__ import unicode_literals import frappe from frappe import _, msgprint, throw diff --git a/erpnext/accounts/doctype/shipping_rule/shipping_rule_dashboard.py b/erpnext/accounts/doctype/shipping_rule/shipping_rule_dashboard.py index 636ee5788d3..fc706211592 100644 --- a/erpnext/accounts/doctype/shipping_rule/shipping_rule_dashboard.py +++ b/erpnext/accounts/doctype/shipping_rule/shipping_rule_dashboard.py @@ -1,5 +1,3 @@ -from __future__ import unicode_literals - from frappe import _ diff --git a/erpnext/accounts/doctype/shipping_rule/test_shipping_rule.py b/erpnext/accounts/doctype/shipping_rule/test_shipping_rule.py index bdd9be3beda..c06dae09701 100644 --- a/erpnext/accounts/doctype/shipping_rule/test_shipping_rule.py +++ b/erpnext/accounts/doctype/shipping_rule/test_shipping_rule.py @@ -1,6 +1,5 @@ # Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors # License: GNU General Public License v3. See license.txt -from __future__ import unicode_literals import unittest diff --git a/erpnext/accounts/doctype/shipping_rule_condition/shipping_rule_condition.py b/erpnext/accounts/doctype/shipping_rule_condition/shipping_rule_condition.py index 66cd269e51b..07f98deb23e 100644 --- a/erpnext/accounts/doctype/shipping_rule_condition/shipping_rule_condition.py +++ b/erpnext/accounts/doctype/shipping_rule_condition/shipping_rule_condition.py @@ -3,7 +3,6 @@ # For license information, please see license.txt -from __future__ import unicode_literals from frappe.model.document import Document diff --git a/erpnext/accounts/doctype/shipping_rule_country/shipping_rule_country.py b/erpnext/accounts/doctype/shipping_rule_country/shipping_rule_country.py index 9576acd0aba..90123c1616e 100644 --- a/erpnext/accounts/doctype/shipping_rule_country/shipping_rule_country.py +++ b/erpnext/accounts/doctype/shipping_rule_country/shipping_rule_country.py @@ -1,8 +1,6 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and contributors # For license information, please see license.txt -from __future__ import unicode_literals from frappe.model.document import Document diff --git a/erpnext/accounts/doctype/subscription/subscription.py b/erpnext/accounts/doctype/subscription/subscription.py index 445eb3c7096..1dae87f2a44 100644 --- a/erpnext/accounts/doctype/subscription/subscription.py +++ b/erpnext/accounts/doctype/subscription/subscription.py @@ -1,9 +1,6 @@ - -# -*- coding: utf-8 -*- # Copyright (c) 2018, Frappe Technologies Pvt. Ltd. and contributors # For license information, please see license.txt -from __future__ import unicode_literals import frappe from frappe import _ @@ -33,7 +30,7 @@ class Subscription(Document): # update start just before the subscription doc is created self.update_subscription_period(self.start_date) - def update_subscription_period(self, date=None): + def update_subscription_period(self, date=None, return_date=False): """ Subscription period is the period to be billed. This method updates the beginning of the billing period and end of the billing period. @@ -41,28 +38,41 @@ class Subscription(Document): The beginning of the billing period is represented in the doctype as `current_invoice_start` and the end of the billing period is represented as `current_invoice_end`. - """ - self.set_current_invoice_start(date) - self.set_current_invoice_end() - def set_current_invoice_start(self, date=None): + If return_date is True, it wont update the start and end dates. + This is implemented to get the dates to check if is_current_invoice_generated """ - This sets the date of the beginning of the current billing period. + _current_invoice_start = self.get_current_invoice_start(date) + _current_invoice_end = self.get_current_invoice_end(_current_invoice_start) + + if return_date: + return _current_invoice_start, _current_invoice_end + + self.current_invoice_start = _current_invoice_start + self.current_invoice_end = _current_invoice_end + + def get_current_invoice_start(self, date=None): + """ + This returns the date of the beginning of the current billing period. If the `date` parameter is not given , it will be automatically set as today's date. """ - if self.is_new_subscription() and self.trial_period_end and getdate(self.trial_period_end) > getdate(self.start_date): - self.current_invoice_start = add_days(self.trial_period_end, 1) - elif self.trial_period_start and self.is_trialling(): - self.current_invoice_start = self.trial_period_start - elif date: - self.current_invoice_start = date - else: - self.current_invoice_start = nowdate() + _current_invoice_start = None - def set_current_invoice_end(self): + if self.is_new_subscription() and self.trial_period_end and getdate(self.trial_period_end) > getdate(self.start_date): + _current_invoice_start = add_days(self.trial_period_end, 1) + elif self.trial_period_start and self.is_trialling(): + _current_invoice_start = self.trial_period_start + elif date: + _current_invoice_start = date + else: + _current_invoice_start = nowdate() + + return _current_invoice_start + + def get_current_invoice_end(self, date=None): """ - This sets the date of the end of the current billing period. + This returns the date of the end of the current billing period. If the subscription is in trial period, it will be set as the end of the trial period. @@ -71,44 +81,47 @@ class Subscription(Document): current billing period where `x` is the billing interval from the `Subscription Plan` in the `Subscription`. """ - if self.is_trialling() and getdate(self.current_invoice_start) < getdate(self.trial_period_end): - self.current_invoice_end = self.trial_period_end + _current_invoice_end = None + + if self.is_trialling() and getdate(date) < getdate(self.trial_period_end): + _current_invoice_end = self.trial_period_end else: billing_cycle_info = self.get_billing_cycle_data() if billing_cycle_info: - if self.is_new_subscription() and getdate(self.start_date) < getdate(self.current_invoice_start): - self.current_invoice_end = add_to_date(self.start_date, **billing_cycle_info) + if self.is_new_subscription() and getdate(self.start_date) < getdate(date): + _current_invoice_end = add_to_date(self.start_date, **billing_cycle_info) # For cases where trial period is for an entire billing interval - if getdate(self.current_invoice_end) < getdate(self.current_invoice_start): - self.current_invoice_end = add_to_date(self.current_invoice_start, **billing_cycle_info) + if getdate(self.current_invoice_end) < getdate(date): + _current_invoice_end = add_to_date(date, **billing_cycle_info) else: - self.current_invoice_end = add_to_date(self.current_invoice_start, **billing_cycle_info) + _current_invoice_end = add_to_date(date, **billing_cycle_info) else: - self.current_invoice_end = get_last_day(self.current_invoice_start) + _current_invoice_end = get_last_day(date) if self.follow_calendar_months: billing_info = self.get_billing_cycle_and_interval() billing_interval_count = billing_info[0]['billing_interval_count'] calendar_months = get_calendar_months(billing_interval_count) calendar_month = 0 - current_invoice_end_month = getdate(self.current_invoice_end).month - current_invoice_end_year = getdate(self.current_invoice_end).year + current_invoice_end_month = getdate(_current_invoice_end).month + current_invoice_end_year = getdate(_current_invoice_end).year for month in calendar_months: if month <= current_invoice_end_month: calendar_month = month if cint(calendar_month - billing_interval_count) <= 0 and \ - getdate(self.current_invoice_start).month != 1: + getdate(date).month != 1: calendar_month = 12 current_invoice_end_year -= 1 - self.current_invoice_end = get_last_day(cstr(current_invoice_end_year) + '-' \ - + cstr(calendar_month) + '-01') + _current_invoice_end = get_last_day(cstr(current_invoice_end_year) + '-' + cstr(calendar_month) + '-01') - if self.end_date and getdate(self.current_invoice_end) > getdate(self.end_date): - self.current_invoice_end = self.end_date + if self.end_date and getdate(_current_invoice_end) > getdate(self.end_date): + _current_invoice_end = self.end_date + + return _current_invoice_end @staticmethod def validate_plans_billing_cycle(billing_cycle_data): @@ -400,6 +413,7 @@ class Subscription(Document): invoice.flags.ignore_mandatory = True + invoice.set_missing_values() invoice.save() if self.submit_invoice: @@ -485,10 +499,13 @@ class Subscription(Document): # Check invoice dates and make sure it doesn't have outstanding invoices return getdate() >= getdate(self.current_invoice_start) - def is_current_invoice_generated(self): + def is_current_invoice_generated(self, _current_start_date=None, _current_end_date=None): invoice = self.get_current_invoice() - if invoice and getdate(self.current_invoice_start) <= getdate(invoice.posting_date) <= getdate(self.current_invoice_end): + if not (_current_start_date and _current_end_date): + _current_start_date, _current_end_date = self.update_subscription_period(date=add_days(self.current_invoice_end, 1), return_date=True) + + if invoice and getdate(_current_start_date) <= getdate(invoice.posting_date) <= getdate(_current_end_date): return True return False @@ -502,13 +519,16 @@ class Subscription(Document): 2. Change the `Subscription` status to 'Past Due Date' 3. Change the `Subscription` status to 'Cancelled' """ - if getdate() > getdate(self.current_invoice_end) and self.is_prepaid_to_invoice(): - self.update_subscription_period(add_days(self.current_invoice_end, 1)) - if not self.is_current_invoice_generated() and (self.is_postpaid_to_invoice() or self.is_prepaid_to_invoice()): + if not self.is_current_invoice_generated(self.current_invoice_start, self.current_invoice_end) \ + and (self.is_postpaid_to_invoice() or self.is_prepaid_to_invoice()): + prorate = frappe.db.get_single_value('Subscription Settings', 'prorate') self.generate_invoice(prorate) + if getdate() > getdate(self.current_invoice_end) and self.is_prepaid_to_invoice(): + self.update_subscription_period(add_days(self.current_invoice_end, 1)) + if self.cancel_at_period_end and getdate() > getdate(self.current_invoice_end): self.cancel_subscription_at_period_end() @@ -545,11 +565,14 @@ class Subscription(Document): self.update_subscription_period(add_days(self.current_invoice_end, 1)) # Generate invoices periodically even if current invoice are unpaid - if self.generate_new_invoices_past_due_date and not self.is_current_invoice_generated() and (self.is_postpaid_to_invoice() - or self.is_prepaid_to_invoice()): + if self.generate_new_invoices_past_due_date and not \ + self.is_current_invoice_generated(self.current_invoice_start, self.current_invoice_end) \ + and (self.is_postpaid_to_invoice() or self.is_prepaid_to_invoice()): + prorate = frappe.db.get_single_value('Subscription Settings', 'prorate') self.generate_invoice(prorate) + @staticmethod def is_paid(invoice): """ diff --git a/erpnext/accounts/doctype/subscription/test_subscription.py b/erpnext/accounts/doctype/subscription/test_subscription.py index e2cf4d5a442..9dd370bd472 100644 --- a/erpnext/accounts/doctype/subscription/test_subscription.py +++ b/erpnext/accounts/doctype/subscription/test_subscription.py @@ -1,7 +1,5 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2018, Frappe Technologies Pvt. Ltd. and Contributors # See license.txt -from __future__ import unicode_literals import unittest @@ -18,6 +16,7 @@ from frappe.utils.data import ( from erpnext.accounts.doctype.subscription.subscription import get_prorata_factor +test_dependencies = ("UOM", "Item Group", "Item") def create_plan(): if not frappe.db.exists('Subscription Plan', '_Test Plan Name'): @@ -68,7 +67,6 @@ def create_plan(): supplier.insert() class TestSubscription(unittest.TestCase): - def setUp(self): create_plan() diff --git a/erpnext/accounts/doctype/subscription_invoice/subscription_invoice.py b/erpnext/accounts/doctype/subscription_invoice/subscription_invoice.py index 687c94cce2c..41f7f9f6f3e 100644 --- a/erpnext/accounts/doctype/subscription_invoice/subscription_invoice.py +++ b/erpnext/accounts/doctype/subscription_invoice/subscription_invoice.py @@ -1,8 +1,6 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2018, Frappe Technologies Pvt. Ltd. and contributors # For license information, please see license.txt -from __future__ import unicode_literals from frappe.model.document import Document diff --git a/erpnext/accounts/doctype/subscription_invoice/test_subscription_invoice.py b/erpnext/accounts/doctype/subscription_invoice/test_subscription_invoice.py index 2cc3038d913..5dc9e32c8e3 100644 --- a/erpnext/accounts/doctype/subscription_invoice/test_subscription_invoice.py +++ b/erpnext/accounts/doctype/subscription_invoice/test_subscription_invoice.py @@ -1,7 +1,5 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2018, Frappe Technologies Pvt. Ltd. and Contributors # See license.txt -from __future__ import unicode_literals import unittest diff --git a/erpnext/accounts/doctype/subscription_plan/subscription_plan.py b/erpnext/accounts/doctype/subscription_plan/subscription_plan.py index c7bb58cb26d..1285343d196 100644 --- a/erpnext/accounts/doctype/subscription_plan/subscription_plan.py +++ b/erpnext/accounts/doctype/subscription_plan/subscription_plan.py @@ -1,8 +1,6 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2018, Frappe Technologies Pvt. Ltd. and contributors # For license information, please see license.txt -from __future__ import unicode_literals import frappe from frappe import _ diff --git a/erpnext/accounts/doctype/subscription_plan/subscription_plan_dashboard.py b/erpnext/accounts/doctype/subscription_plan/subscription_plan_dashboard.py index df3023335a3..d076e39964b 100644 --- a/erpnext/accounts/doctype/subscription_plan/subscription_plan_dashboard.py +++ b/erpnext/accounts/doctype/subscription_plan/subscription_plan_dashboard.py @@ -1,5 +1,3 @@ -from __future__ import unicode_literals - from frappe import _ diff --git a/erpnext/accounts/doctype/subscription_plan/test_subscription_plan.py b/erpnext/accounts/doctype/subscription_plan/test_subscription_plan.py index ba997632479..3b6ab605a45 100644 --- a/erpnext/accounts/doctype/subscription_plan/test_subscription_plan.py +++ b/erpnext/accounts/doctype/subscription_plan/test_subscription_plan.py @@ -1,7 +1,5 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2018, Frappe Technologies Pvt. Ltd. and Contributors # See license.txt -from __future__ import unicode_literals import unittest diff --git a/erpnext/accounts/doctype/subscription_plan_detail/subscription_plan_detail.py b/erpnext/accounts/doctype/subscription_plan_detail/subscription_plan_detail.py index a63a27700cc..d22a73f25d7 100644 --- a/erpnext/accounts/doctype/subscription_plan_detail/subscription_plan_detail.py +++ b/erpnext/accounts/doctype/subscription_plan_detail/subscription_plan_detail.py @@ -1,8 +1,6 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2018, Frappe Technologies Pvt. Ltd. and contributors # For license information, please see license.txt -from __future__ import unicode_literals from frappe.model.document import Document diff --git a/erpnext/accounts/doctype/subscription_settings/subscription_settings.py b/erpnext/accounts/doctype/subscription_settings/subscription_settings.py index 54735834baa..12580db1ede 100644 --- a/erpnext/accounts/doctype/subscription_settings/subscription_settings.py +++ b/erpnext/accounts/doctype/subscription_settings/subscription_settings.py @@ -1,8 +1,6 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2018, Frappe Technologies Pvt. Ltd. and contributors # For license information, please see license.txt -from __future__ import unicode_literals from frappe.model.document import Document diff --git a/erpnext/accounts/doctype/subscription_settings/test_subscription_settings.py b/erpnext/accounts/doctype/subscription_settings/test_subscription_settings.py index 5875ee069ec..63eae3bfeb3 100644 --- a/erpnext/accounts/doctype/subscription_settings/test_subscription_settings.py +++ b/erpnext/accounts/doctype/subscription_settings/test_subscription_settings.py @@ -1,7 +1,5 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2018, Frappe Technologies Pvt. Ltd. and Contributors # See license.txt -from __future__ import unicode_literals import unittest diff --git a/erpnext/accounts/doctype/tax_category/tax_category.py b/erpnext/accounts/doctype/tax_category/tax_category.py index df31a5e45f9..18cf72ad59f 100644 --- a/erpnext/accounts/doctype/tax_category/tax_category.py +++ b/erpnext/accounts/doctype/tax_category/tax_category.py @@ -1,8 +1,6 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2018, Frappe Technologies Pvt. Ltd. and contributors # For license information, please see license.txt -from __future__ import unicode_literals from frappe.model.document import Document diff --git a/erpnext/accounts/doctype/tax_category/tax_category_dashboard.py b/erpnext/accounts/doctype/tax_category/tax_category_dashboard.py index d643efb090b..4bdb70a480a 100644 --- a/erpnext/accounts/doctype/tax_category/tax_category_dashboard.py +++ b/erpnext/accounts/doctype/tax_category/tax_category_dashboard.py @@ -1,5 +1,3 @@ -from __future__ import unicode_literals - from frappe import _ diff --git a/erpnext/accounts/doctype/tax_category/test_tax_category.py b/erpnext/accounts/doctype/tax_category/test_tax_category.py index 90931058f07..e3b3430ace5 100644 --- a/erpnext/accounts/doctype/tax_category/test_tax_category.py +++ b/erpnext/accounts/doctype/tax_category/test_tax_category.py @@ -1,7 +1,5 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2018, Frappe Technologies Pvt. Ltd. and Contributors # See license.txt -from __future__ import unicode_literals import unittest diff --git a/erpnext/accounts/doctype/tax_rule/tax_rule.py b/erpnext/accounts/doctype/tax_rule/tax_rule.py index 150498d6acc..a16377c847c 100644 --- a/erpnext/accounts/doctype/tax_rule/tax_rule.py +++ b/erpnext/accounts/doctype/tax_rule/tax_rule.py @@ -1,8 +1,6 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and contributors # For license information, please see license.txt -from __future__ import unicode_literals import functools @@ -12,8 +10,6 @@ from frappe.contacts.doctype.address.address import get_default_address from frappe.model.document import Document from frappe.utils import cint, cstr from frappe.utils.nestedset import get_root_of -from past.builtins import cmp -from six import iteritems from erpnext.setup.doctype.customer_group.customer_group import get_parent_customer_groups @@ -151,7 +147,7 @@ def get_tax_template(posting_date, args): if 'tax_category' in args.keys(): del args['tax_category'] - for key, value in iteritems(args): + for key, value in args.items(): if key=="use_for_shopping_cart": conditions.append("use_for_shopping_cart = {0}".format(1 if value else 0)) elif key == 'customer_group': @@ -172,6 +168,10 @@ def get_tax_template(posting_date, args): for key in args: if rule.get(key): rule.no_of_keys_matched += 1 + def cmp(a, b): + # refernce: https://docs.python.org/3.0/whatsnew/3.0.html#ordering-comparisons + return int(a > b) - int(a < b) + rule = sorted(tax_rule, key = functools.cmp_to_key(lambda b, a: cmp(a.no_of_keys_matched, b.no_of_keys_matched) or diff --git a/erpnext/accounts/doctype/tax_rule/test_tax_rule.py b/erpnext/accounts/doctype/tax_rule/test_tax_rule.py index f937274edf5..d5ac9b20c55 100644 --- a/erpnext/accounts/doctype/tax_rule/test_tax_rule.py +++ b/erpnext/accounts/doctype/tax_rule/test_tax_rule.py @@ -1,7 +1,5 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors # See license.txt -from __future__ import unicode_literals import unittest @@ -13,7 +11,6 @@ from erpnext.crm.doctype.opportunity.test_opportunity import make_opportunity test_records = frappe.get_test_records('Tax Rule') -from six import iteritems class TestTaxRule(unittest.TestCase): @@ -177,7 +174,7 @@ def make_tax_rule(**args): tax_rule = frappe.new_doc("Tax Rule") - for key, val in iteritems(args): + for key, val in args.items(): if key != "save": tax_rule.set(key, val) diff --git a/erpnext/accounts/doctype/tax_withholding_account/tax_withholding_account.py b/erpnext/accounts/doctype/tax_withholding_account/tax_withholding_account.py index fd194829e56..c8d9d45ec75 100644 --- a/erpnext/accounts/doctype/tax_withholding_account/tax_withholding_account.py +++ b/erpnext/accounts/doctype/tax_withholding_account/tax_withholding_account.py @@ -1,8 +1,6 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2018, Frappe Technologies Pvt. Ltd. and contributors # For license information, please see license.txt -from __future__ import unicode_literals from frappe.model.document import Document diff --git a/erpnext/accounts/doctype/tax_withholding_category/tax_withholding_category.js b/erpnext/accounts/doctype/tax_withholding_category/tax_withholding_category.js index b8d6c9af3a9..7b479749465 100644 --- a/erpnext/accounts/doctype/tax_withholding_category/tax_withholding_category.js +++ b/erpnext/accounts/doctype/tax_withholding_category/tax_withholding_category.js @@ -8,7 +8,8 @@ frappe.ui.form.on('Tax Withholding Category', { if (child.company) { return { filters: { - 'company': child.company + 'company': child.company, + 'root_type': ['in', ['Asset', 'Liability']] } }; } diff --git a/erpnext/accounts/doctype/tax_withholding_category/tax_withholding_category.py b/erpnext/accounts/doctype/tax_withholding_category/tax_withholding_category.py index b4bdd73c492..dc1818a052a 100644 --- a/erpnext/accounts/doctype/tax_withholding_category/tax_withholding_category.py +++ b/erpnext/accounts/doctype/tax_withholding_category/tax_withholding_category.py @@ -1,19 +1,41 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2018, Frappe Technologies Pvt. Ltd. and contributors # For license information, please see license.txt -from __future__ import unicode_literals import frappe from frappe import _ from frappe.model.document import Document from frappe.utils import cint, getdate -from erpnext.accounts.utils import get_fiscal_year - class TaxWithholdingCategory(Document): - pass + def validate(self): + self.validate_dates() + self.validate_accounts() + self.validate_thresholds() + + def validate_dates(self): + last_date = None + for d in self.get('rates'): + if getdate(d.from_date) >= getdate(d.to_date): + frappe.throw(_("Row #{0}: From Date cannot be before To Date").format(d.idx)) + + # validate overlapping of dates + if last_date and getdate(d.to_date) < getdate(last_date): + frappe.throw(_("Row #{0}: Dates overlapping with other row").format(d.idx)) + + def validate_accounts(self): + existing_accounts = [] + for d in self.get('accounts'): + if d.get('account') in existing_accounts: + frappe.throw(_("Account {0} added multiple times").format(frappe.bold(d.get('account')))) + + existing_accounts.append(d.get('account')) + + def validate_thresholds(self): + for d in self.get('rates'): + if d.cumulative_threshold and d.cumulative_threshold < d.single_threshold: + frappe.throw(_("Row #{0}: Cumulative threshold cannot be less than Single Transaction threshold").format(d.idx)) def get_party_details(inv): party_type, party = '', '' @@ -34,15 +56,24 @@ def get_party_tax_withholding_details(inv, tax_withholding_category=None): pan_no = '' parties = [] party_type, party = get_party_details(inv) + has_pan_field = frappe.get_meta(party_type).has_field("pan") if not tax_withholding_category: - tax_withholding_category, pan_no = frappe.db.get_value(party_type, party, ['tax_withholding_category', 'pan']) + if has_pan_field: + fields = ['tax_withholding_category', 'pan'] + else: + fields = ['tax_withholding_category'] + + tax_withholding_details = frappe.db.get_value(party_type, party, fields, as_dict=1) + + tax_withholding_category = tax_withholding_details.get('tax_withholding_category') + pan_no = tax_withholding_details.get('pan') if not tax_withholding_category: return # if tax_withholding_category passed as an argument but not pan_no - if not pan_no: + if not pan_no and has_pan_field: pan_no = frappe.db.get_value(party_type, party, 'pan') # Get others suppliers with the same PAN No @@ -52,8 +83,8 @@ def get_party_tax_withholding_details(inv, tax_withholding_category=None): if not parties: parties.append(party) - fiscal_year = get_fiscal_year(inv.get('posting_date') or inv.get('transaction_date'), company=inv.company) - tax_details = get_tax_withholding_details(tax_withholding_category, fiscal_year[0], inv.company) + posting_date = inv.get('posting_date') or inv.get('transaction_date') + tax_details = get_tax_withholding_details(tax_withholding_category, posting_date, inv.company) if not tax_details: frappe.throw(_('Please set associated account in Tax Withholding Category {0} against Company {1}') @@ -67,7 +98,7 @@ def get_party_tax_withholding_details(inv, tax_withholding_category=None): tax_amount, tax_deducted = get_tax_amount( party_type, parties, inv, tax_details, - fiscal_year, pan_no + posting_date, pan_no ) if party_type == 'Supplier': @@ -77,16 +108,19 @@ def get_party_tax_withholding_details(inv, tax_withholding_category=None): return tax_row -def get_tax_withholding_details(tax_withholding_category, fiscal_year, company): +def get_tax_withholding_details(tax_withholding_category, posting_date, company): tax_withholding = frappe.get_doc("Tax Withholding Category", tax_withholding_category) - tax_rate_detail = get_tax_withholding_rates(tax_withholding, fiscal_year) + tax_rate_detail = get_tax_withholding_rates(tax_withholding, posting_date) for account_detail in tax_withholding.accounts: if company == account_detail.company: return frappe._dict({ + "tax_withholding_category": tax_withholding_category, "account_head": account_detail.account, "rate": tax_rate_detail.tax_withholding_rate, + "from_date": tax_rate_detail.from_date, + "to_date": tax_rate_detail.to_date, "threshold": tax_rate_detail.single_threshold, "cumulative_threshold": tax_rate_detail.cumulative_threshold, "description": tax_withholding.category_name if tax_withholding.category_name else tax_withholding_category, @@ -95,13 +129,13 @@ def get_tax_withholding_details(tax_withholding_category, fiscal_year, company): "round_off_tax_amount": tax_withholding.round_off_tax_amount }) -def get_tax_withholding_rates(tax_withholding, fiscal_year): +def get_tax_withholding_rates(tax_withholding, posting_date): # returns the row that matches with the fiscal year from posting date for rate in tax_withholding.rates: - if rate.fiscal_year == fiscal_year: + if getdate(rate.from_date) <= getdate(posting_date) <= getdate(rate.to_date): return rate - frappe.throw(_("No Tax Withholding data found for the current Fiscal Year.")) + frappe.throw(_("No Tax Withholding data found for the current posting date.")) def get_tax_row_for_tcs(inv, tax_details, tax_amount, tax_deducted): row = { @@ -143,38 +177,39 @@ def get_tax_row_for_tds(tax_details, tax_amount): "account_head": tax_details.account_head } -def get_lower_deduction_certificate(fiscal_year, pan_no): - ldc_name = frappe.db.get_value('Lower Deduction Certificate', { 'pan_no': pan_no, 'fiscal_year': fiscal_year }, 'name') +def get_lower_deduction_certificate(tax_details, pan_no): + ldc_name = frappe.db.get_value('Lower Deduction Certificate', + { + 'pan_no': pan_no, + 'tax_withholding_category': tax_details.tax_withholding_category, + 'valid_from': ('>=', tax_details.from_date), + 'valid_upto': ('<=', tax_details.to_date) + }, 'name') + if ldc_name: return frappe.get_doc('Lower Deduction Certificate', ldc_name) -def get_tax_amount(party_type, parties, inv, tax_details, fiscal_year_details, pan_no=None): - fiscal_year = fiscal_year_details[0] - - - vouchers = get_invoice_vouchers(parties, fiscal_year, inv.company, party_type=party_type) - advance_vouchers = get_advance_vouchers(parties, fiscal_year, inv.company, party_type=party_type) +def get_tax_amount(party_type, parties, inv, tax_details, posting_date, pan_no=None): + vouchers = get_invoice_vouchers(parties, tax_details, inv.company, party_type=party_type) + advance_vouchers = get_advance_vouchers(parties, company=inv.company, from_date=tax_details.from_date, + to_date=tax_details.to_date, party_type=party_type) taxable_vouchers = vouchers + advance_vouchers tax_deducted = 0 if taxable_vouchers: - tax_deducted = get_deducted_tax(taxable_vouchers, fiscal_year, tax_details) + tax_deducted = get_deducted_tax(taxable_vouchers, tax_details) tax_amount = 0 - posting_date = inv.get('posting_date') or inv.get('transaction_date') if party_type == 'Supplier': - ldc = get_lower_deduction_certificate(fiscal_year, pan_no) + ldc = get_lower_deduction_certificate(tax_details, pan_no) if tax_deducted: net_total = inv.net_total if ldc: - tax_amount = get_tds_amount_from_ldc(ldc, parties, fiscal_year, pan_no, tax_details, posting_date, net_total) + tax_amount = get_tds_amount_from_ldc(ldc, parties, pan_no, tax_details, posting_date, net_total) else: tax_amount = net_total * tax_details.rate / 100 if net_total > 0 else 0 else: - tax_amount = get_tds_amount( - ldc, parties, inv, tax_details, - fiscal_year_details, tax_deducted, vouchers - ) + tax_amount = get_tds_amount(ldc, parties, inv, tax_details, tax_deducted, vouchers) elif party_type == 'Customer': if tax_deducted: @@ -183,29 +218,50 @@ def get_tax_amount(party_type, parties, inv, tax_details, fiscal_year_details, p else: # if no TCS has been charged in FY, # then chargeable value is "prev invoices + advances" value which cross the threshold - tax_amount = get_tcs_amount( - parties, inv, tax_details, - fiscal_year_details, vouchers, advance_vouchers - ) + tax_amount = get_tcs_amount(parties, inv, tax_details, vouchers, advance_vouchers) + + if cint(tax_details.round_off_tax_amount): + tax_amount = round(tax_amount) return tax_amount, tax_deducted -def get_invoice_vouchers(parties, fiscal_year, company, party_type='Supplier'): +def get_invoice_vouchers(parties, tax_details, company, party_type='Supplier'): dr_or_cr = 'credit' if party_type == 'Supplier' else 'debit' + doctype = 'Purchase Invoice' if party_type == 'Supplier' else 'Sales Invoice' filters = { - dr_or_cr: ['>', 0], 'company': company, - 'party_type': party_type, - 'party': ['in', parties], - 'fiscal_year': fiscal_year, + frappe.scrub(party_type): ['in', parties], + 'posting_date': ['between', (tax_details.from_date, tax_details.to_date)], 'is_opening': 'No', - 'is_cancelled': 0 + 'docstatus': 1 } - return frappe.get_all('GL Entry', filters=filters, distinct=1, pluck="voucher_no") or [""] + if not tax_details.get('consider_party_ledger_amount') and doctype != "Sales Invoice": + filters.update({ + 'apply_tds': 1, + 'tax_withholding_category': tax_details.get('tax_withholding_category') + }) -def get_advance_vouchers(parties, fiscal_year=None, company=None, from_date=None, to_date=None, party_type='Supplier'): + invoices = frappe.get_all(doctype, filters=filters, pluck="name") or [""] + + journal_entries = frappe.db.sql(""" + SELECT j.name + FROM `tabJournal Entry` j, `tabJournal Entry Account` ja + WHERE + j.docstatus = 1 + AND j.is_opening = 'No' + AND j.posting_date between %s and %s + AND ja.{dr_or_cr} > 0 + AND ja.party in %s + """.format(dr_or_cr=dr_or_cr), (tax_details.from_date, tax_details.to_date, tuple(parties)), as_list=1) + + if journal_entries: + journal_entries = journal_entries[0] + + return invoices + journal_entries + +def get_advance_vouchers(parties, company=None, from_date=None, to_date=None, party_type='Supplier'): # for advance vouchers, debit and credit is reversed dr_or_cr = 'debit' if party_type == 'Supplier' else 'credit' @@ -218,8 +274,6 @@ def get_advance_vouchers(parties, fiscal_year=None, company=None, from_date=None 'against_voucher': ['is', 'not set'] } - if fiscal_year: - filters['fiscal_year'] = fiscal_year if company: filters['company'] = company if from_date and to_date: @@ -227,20 +281,21 @@ def get_advance_vouchers(parties, fiscal_year=None, company=None, from_date=None return frappe.get_all('GL Entry', filters=filters, distinct=1, pluck='voucher_no') or [""] -def get_deducted_tax(taxable_vouchers, fiscal_year, tax_details): +def get_deducted_tax(taxable_vouchers, tax_details): # check if TDS / TCS account is already charged on taxable vouchers filters = { 'is_cancelled': 0, 'credit': ['>', 0], - 'fiscal_year': fiscal_year, + 'posting_date': ['between', (tax_details.from_date, tax_details.to_date)], 'account': tax_details.account_head, 'voucher_no': ['in', taxable_vouchers], } - field = "sum(credit)" + field = "credit" - return frappe.db.get_value('GL Entry', filters, field) or 0.0 + entries = frappe.db.get_all('GL Entry', filters, pluck=field) + return sum(entries) -def get_tds_amount(ldc, parties, inv, tax_details, fiscal_year_details, tax_deducted, vouchers): +def get_tds_amount(ldc, parties, inv, tax_details, tax_deducted, vouchers): tds_amount = 0 invoice_filters = { 'name': ('in', vouchers), @@ -264,7 +319,7 @@ def get_tds_amount(ldc, parties, inv, tax_details, fiscal_year_details, tax_dedu supp_credit_amt += supp_jv_credit_amt supp_credit_amt += inv.net_total - debit_note_amount = get_debit_note_amount(parties, fiscal_year_details, inv.company) + debit_note_amount = get_debit_note_amount(parties, tax_details.from_date, tax_details.to_date, inv.company) supp_credit_amt -= debit_note_amount threshold = tax_details.get('threshold', 0) @@ -287,14 +342,10 @@ def get_tds_amount(ldc, parties, inv, tax_details, fiscal_year_details, tax_dedu else: tds_amount = supp_credit_amt * tax_details.rate / 100 if supp_credit_amt > 0 else 0 - if cint(tax_details.round_off_tax_amount): - tds_amount = round(tds_amount) - return tds_amount -def get_tcs_amount(parties, inv, tax_details, fiscal_year_details, vouchers, adv_vouchers): +def get_tcs_amount(parties, inv, tax_details, vouchers, adv_vouchers): tcs_amount = 0 - fiscal_year, _, _ = fiscal_year_details # sum of debit entries made from sales invoices invoiced_amt = frappe.db.get_value('GL Entry', { @@ -313,21 +364,21 @@ def get_tcs_amount(parties, inv, tax_details, fiscal_year_details, vouchers, adv }, 'sum(credit)') or 0.0 # sum of credit entries made from sales invoice - credit_note_amt = frappe.db.get_value('GL Entry', { + credit_note_amt = sum(frappe.db.get_all('GL Entry', { 'is_cancelled': 0, 'credit': ['>', 0], 'party': ['in', parties], - 'fiscal_year': fiscal_year, + 'posting_date': ['between', (tax_details.from_date, tax_details.to_date)], 'company': inv.company, 'voucher_type': 'Sales Invoice', - }, 'sum(credit)') or 0.0 + }, pluck='credit')) cumulative_threshold = tax_details.get('cumulative_threshold', 0) current_invoice_total = get_invoice_total_without_tcs(inv, tax_details) total_invoiced_amt = current_invoice_total + invoiced_amt + advance_amt - credit_note_amt - if ((cumulative_threshold and total_invoiced_amt >= cumulative_threshold)): + if (cumulative_threshold and total_invoiced_amt >= cumulative_threshold): chargeable_amt = total_invoiced_amt - cumulative_threshold tcs_amount = chargeable_amt * tax_details.rate / 100 if chargeable_amt > 0 else 0 @@ -339,7 +390,7 @@ def get_invoice_total_without_tcs(inv, tax_details): return inv.grand_total - tcs_tax_row_amount -def get_tds_amount_from_ldc(ldc, parties, fiscal_year, pan_no, tax_details, posting_date, net_total): +def get_tds_amount_from_ldc(ldc, parties, pan_no, tax_details, posting_date, net_total): tds_amount = 0 limit_consumed = frappe.db.get_value('Purchase Invoice', { 'supplier': ('in', parties), @@ -356,14 +407,13 @@ def get_tds_amount_from_ldc(ldc, parties, fiscal_year, pan_no, tax_details, post return tds_amount -def get_debit_note_amount(suppliers, fiscal_year_details, company=None): - _, year_start_date, year_end_date = fiscal_year_details +def get_debit_note_amount(suppliers, from_date, to_date, company=None): filters = { 'supplier': ['in', suppliers], 'is_return': 1, 'docstatus': 1, - 'posting_date': ['between', (year_start_date, year_end_date)] + 'posting_date': ['between', (from_date, to_date)] } fields = ['abs(sum(net_total)) as net_total'] diff --git a/erpnext/accounts/doctype/tax_withholding_category/tax_withholding_category_dashboard.py b/erpnext/accounts/doctype/tax_withholding_category/tax_withholding_category_dashboard.py index 152ee460814..256d4ac2178 100644 --- a/erpnext/accounts/doctype/tax_withholding_category/tax_withholding_category_dashboard.py +++ b/erpnext/accounts/doctype/tax_withholding_category/tax_withholding_category_dashboard.py @@ -1,6 +1,3 @@ -from __future__ import unicode_literals - - def get_data(): return { 'fieldname': 'tax_withholding_category', diff --git a/erpnext/accounts/doctype/tax_withholding_category/test_tax_withholding_category.py b/erpnext/accounts/doctype/tax_withholding_category/test_tax_withholding_category.py index c4a5ba52fea..a3fcf7da7a5 100644 --- a/erpnext/accounts/doctype/tax_withholding_category/test_tax_withholding_category.py +++ b/erpnext/accounts/doctype/tax_withholding_category/test_tax_withholding_category.py @@ -1,7 +1,5 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2018, Frappe Technologies Pvt. Ltd. and Contributors # See license.txt -from __future__ import unicode_literals import unittest @@ -176,6 +174,29 @@ class TestTaxWithholdingCategory(unittest.TestCase): for d in invoices: d.cancel() + def test_multi_category_single_supplier(self): + frappe.db.set_value("Supplier", "Test TDS Supplier5", "tax_withholding_category", "Test Service Category") + invoices = [] + + pi = create_purchase_invoice(supplier = "Test TDS Supplier5", rate = 500, do_not_save=True) + pi.tax_withholding_category = "Test Service Category" + pi.save() + pi.submit() + invoices.append(pi) + + # Second Invoice will apply TDS checked + pi1 = create_purchase_invoice(supplier = "Test TDS Supplier5", rate = 2500, do_not_save=True) + pi1.tax_withholding_category = "Test Goods Category" + pi1.save() + pi1.submit() + invoices.append(pi1) + + self.assertEqual(pi1.taxes[0].tax_amount, 250) + + #delete invoices to avoid clashing + for d in invoices: + d.cancel() + def cancel_invoices(): purchase_invoices = frappe.get_all("Purchase Invoice", { 'supplier': ['in', ['Test TDS Supplier', 'Test TDS Supplier1', 'Test TDS Supplier2']], @@ -251,7 +272,8 @@ def create_sales_invoice(**args): def create_records(): # create a new suppliers - for name in ['Test TDS Supplier', 'Test TDS Supplier1', 'Test TDS Supplier2', 'Test TDS Supplier3', 'Test TDS Supplier4']: + for name in ['Test TDS Supplier', 'Test TDS Supplier1', 'Test TDS Supplier2', 'Test TDS Supplier3', + 'Test TDS Supplier4', 'Test TDS Supplier5']: if frappe.db.exists('Supplier', name): continue @@ -313,16 +335,16 @@ def create_records(): }).insert() def create_tax_with_holding_category(): - fiscal_year = get_fiscal_year(today(), company="_Test Company")[0] - - # Cummulative thresold + fiscal_year = get_fiscal_year(today(), company="_Test Company") + # Cumulative threshold if not frappe.db.exists("Tax Withholding Category", "Cumulative Threshold TDS"): frappe.get_doc({ "doctype": "Tax Withholding Category", "name": "Cumulative Threshold TDS", "category_name": "10% TDS", "rates": [{ - 'fiscal_year': fiscal_year, + 'from_date': fiscal_year[1], + 'to_date': fiscal_year[2], 'tax_withholding_rate': 10, 'single_threshold': 0, 'cumulative_threshold': 30000.00 @@ -339,7 +361,8 @@ def create_tax_with_holding_category(): "name": "Cumulative Threshold TCS", "category_name": "10% TCS", "rates": [{ - 'fiscal_year': fiscal_year, + 'from_date': fiscal_year[1], + 'to_date': fiscal_year[2], 'tax_withholding_rate': 10, 'single_threshold': 0, 'cumulative_threshold': 30000.00 @@ -357,7 +380,8 @@ def create_tax_with_holding_category(): "name": "Single Threshold TDS", "category_name": "10% TDS", "rates": [{ - 'fiscal_year': fiscal_year, + 'from_date': fiscal_year[1], + 'to_date': fiscal_year[2], 'tax_withholding_rate': 10, 'single_threshold': 20000.00, 'cumulative_threshold': 0 @@ -377,7 +401,8 @@ def create_tax_with_holding_category(): "consider_party_ledger_amount": 1, "tax_on_excess_amount": 1, "rates": [{ - 'fiscal_year': fiscal_year, + 'from_date': fiscal_year[1], + 'to_date': fiscal_year[2], 'tax_withholding_rate': 10, 'single_threshold': 0, 'cumulative_threshold': 30000 @@ -387,3 +412,39 @@ def create_tax_with_holding_category(): 'account': 'TDS - _TC' }] }).insert() + + if not frappe.db.exists("Tax Withholding Category", "Test Service Category"): + frappe.get_doc({ + "doctype": "Tax Withholding Category", + "name": "Test Service Category", + "category_name": "Test Service Category", + "rates": [{ + 'from_date': fiscal_year[1], + 'to_date': fiscal_year[2], + 'tax_withholding_rate': 10, + 'single_threshold': 2000, + 'cumulative_threshold': 2000 + }], + "accounts": [{ + 'company': '_Test Company', + 'account': 'TDS - _TC' + }] + }).insert() + + if not frappe.db.exists("Tax Withholding Category", "Test Goods Category"): + frappe.get_doc({ + "doctype": "Tax Withholding Category", + "name": "Test Goods Category", + "category_name": "Test Goods Category", + "rates": [{ + 'from_date': fiscal_year[1], + 'to_date': fiscal_year[2], + 'tax_withholding_rate': 10, + 'single_threshold': 2000, + 'cumulative_threshold': 2000 + }], + "accounts": [{ + 'company': '_Test Company', + 'account': 'TDS - _TC' + }] + }).insert() diff --git a/erpnext/accounts/doctype/tax_withholding_rate/tax_withholding_rate.json b/erpnext/accounts/doctype/tax_withholding_rate/tax_withholding_rate.json index 1e8194af6e4..d2c505c6300 100644 --- a/erpnext/accounts/doctype/tax_withholding_rate/tax_withholding_rate.json +++ b/erpnext/accounts/doctype/tax_withholding_rate/tax_withholding_rate.json @@ -1,202 +1,72 @@ { - "allow_copy": 0, - "allow_guest_to_view": 0, - "allow_import": 0, - "allow_rename": 0, - "beta": 0, - "creation": "2018-07-17 16:53:13.716665", - "custom": 0, - "docstatus": 0, - "doctype": "DocType", - "document_type": "", - "editable_grid": 1, - "engine": "InnoDB", + "actions": [], + "creation": "2018-07-17 16:53:13.716665", + "doctype": "DocType", + "editable_grid": 1, + "engine": "InnoDB", + "field_order": [ + "from_date", + "to_date", + "tax_withholding_rate", + "column_break_3", + "single_threshold", + "cumulative_threshold" + ], "fields": [ { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 2, - "fieldname": "fiscal_year", - "fieldtype": "Link", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 1, - "in_standard_filter": 0, - "label": "Fiscal Year", - "length": 0, - "no_copy": 0, - "options": "Fiscal Year", - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 1, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 - }, + "columns": 1, + "fieldname": "tax_withholding_rate", + "fieldtype": "Float", + "in_list_view": 1, + "label": "Tax Withholding Rate", + "reqd": 1 + }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 2, - "fieldname": "tax_withholding_rate", - "fieldtype": "Float", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 1, - "in_standard_filter": 0, - "label": "Tax Withholding Rate", - "length": 0, - "no_copy": 0, - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 1, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 - }, + "fieldname": "column_break_3", + "fieldtype": "Column Break" + }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "column_break_3", - "fieldtype": "Column Break", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "length": 0, - "no_copy": 0, - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 - }, + "columns": 2, + "fieldname": "single_threshold", + "fieldtype": "Currency", + "in_list_view": 1, + "label": "Single Transaction Threshold" + }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 3, - "fieldname": "single_threshold", - "fieldtype": "Currency", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 1, - "in_standard_filter": 0, - "label": "Single Transaction Threshold", - "length": 0, - "no_copy": 0, - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 - }, + "columns": 3, + "fieldname": "cumulative_threshold", + "fieldtype": "Currency", + "in_list_view": 1, + "label": "Cumulative Transaction Threshold" + }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 3, - "fieldname": "cumulative_threshold", - "fieldtype": "Currency", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 1, - "in_standard_filter": 0, - "label": "Cumulative Transaction Threshold", - "length": 0, - "no_copy": 0, - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 + "columns": 2, + "fieldname": "from_date", + "fieldtype": "Date", + "in_list_view": 1, + "label": "From Date", + "reqd": 1 + }, + { + "columns": 2, + "fieldname": "to_date", + "fieldtype": "Date", + "in_list_view": 1, + "label": "To Date", + "reqd": 1 } - ], - "has_web_view": 0, - "hide_heading": 0, - "hide_toolbar": 0, - "idx": 0, - "image_view": 0, - "in_create": 0, - "is_submittable": 0, - "issingle": 0, - "istable": 1, - "max_attachments": 0, - "modified": "2018-07-17 17:13:09.819580", - "modified_by": "Administrator", - "module": "Accounts", - "name": "Tax Withholding Rate", - "name_case": "", - "owner": "Administrator", - "permissions": [], - "quick_entry": 1, - "read_only": 0, - "read_only_onload": 0, - "show_name_in_global_search": 0, - "sort_field": "modified", - "sort_order": "DESC", - "track_changes": 1, - "track_seen": 0, - "track_views": 0 + ], + "index_web_pages_for_search": 1, + "istable": 1, + "links": [], + "modified": "2021-08-31 11:42:12.213977", + "modified_by": "Administrator", + "module": "Accounts", + "name": "Tax Withholding Rate", + "owner": "Administrator", + "permissions": [], + "quick_entry": 1, + "sort_field": "modified", + "sort_order": "DESC", + "track_changes": 1 } \ No newline at end of file diff --git a/erpnext/accounts/doctype/tax_withholding_rate/tax_withholding_rate.py b/erpnext/accounts/doctype/tax_withholding_rate/tax_withholding_rate.py index 6556277509a..16cbccc8bea 100644 --- a/erpnext/accounts/doctype/tax_withholding_rate/tax_withholding_rate.py +++ b/erpnext/accounts/doctype/tax_withholding_rate/tax_withholding_rate.py @@ -1,8 +1,6 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2018, Frappe Technologies Pvt. Ltd. and contributors # For license information, please see license.txt -from __future__ import unicode_literals from frappe.model.document import Document diff --git a/erpnext/accounts/general_ledger.py b/erpnext/accounts/general_ledger.py index 4bf2b828edd..8ef7d7e103c 100644 --- a/erpnext/accounts/general_ledger.py +++ b/erpnext/accounts/general_ledger.py @@ -1,7 +1,6 @@ # Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors # License: GNU General Public License v3. See license.txt -from __future__ import unicode_literals import frappe from frappe import _ @@ -284,13 +283,16 @@ def check_freezing_date(posting_date, adv_adj=False): """ Nobody can do GL Entries where posting date is before freezing date except authorized person + + Administrator has all the roles so this check will be bypassed if any role is allowed to post + Hence stop admin to bypass if accounts are freezed """ if not adv_adj: acc_frozen_upto = frappe.db.get_value('Accounts Settings', None, 'acc_frozen_upto') if acc_frozen_upto: frozen_accounts_modifier = frappe.db.get_value( 'Accounts Settings', None,'frozen_accounts_modifier') if getdate(posting_date) <= getdate(acc_frozen_upto) \ - and not frozen_accounts_modifier in frappe.get_roles(): + and (frozen_accounts_modifier not in frappe.get_roles() or frappe.session.user == 'Administrator'): frappe.throw(_("You are not authorized to add or update entries before {0}").format(formatdate(acc_frozen_upto))) def set_as_cancel(voucher_type, voucher_no): diff --git a/erpnext/accounts/notification/notification_for_new_fiscal_year/notification_for_new_fiscal_year.py b/erpnext/accounts/notification/notification_for_new_fiscal_year/notification_for_new_fiscal_year.py index f57de916dd1..02e3e933330 100644 --- a/erpnext/accounts/notification/notification_for_new_fiscal_year/notification_for_new_fiscal_year.py +++ b/erpnext/accounts/notification/notification_for_new_fiscal_year/notification_for_new_fiscal_year.py @@ -1,6 +1,3 @@ -from __future__ import unicode_literals - - def get_context(context): # do your magic here pass diff --git a/erpnext/accounts/page/__init__.py b/erpnext/accounts/page/__init__.py index baffc488252..e69de29bb2d 100644 --- a/erpnext/accounts/page/__init__.py +++ b/erpnext/accounts/page/__init__.py @@ -1 +0,0 @@ -from __future__ import unicode_literals diff --git a/erpnext/accounts/party.py b/erpnext/accounts/party.py index 7ea6ccee5b4..e904768b386 100644 --- a/erpnext/accounts/party.py +++ b/erpnext/accounts/party.py @@ -1,7 +1,6 @@ # Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors # License: GNU General Public License v3. See license.txt -from __future__ import unicode_literals import frappe from frappe import _, msgprint, scrub @@ -27,7 +26,6 @@ from frappe.utils import ( getdate, nowdate, ) -from six import iteritems import erpnext from erpnext import get_company_currency @@ -85,7 +83,8 @@ def _get_party_details(party=None, account=None, party_type="Customer", company= if party_type=="Customer": party_details["sales_team"] = [{ "sales_person": d.sales_person, - "allocated_percentage": d.allocated_percentage or None + "allocated_percentage": d.allocated_percentage or None, + "commission_rate": d.commission_rate } for d in party.get("sales_team")] # supplier tax withholding category @@ -220,7 +219,7 @@ def set_account_and_due_date(party, account, party_type, company, posting_date, return out @frappe.whitelist() -def get_party_account(party_type, party, company=None): +def get_party_account(party_type, party=None, company=None): """Returns the account for the given `party`. Will first search in party (Customer / Supplier) record, if not found, will search in group (Customer Group / Supplier Group), @@ -228,8 +227,11 @@ def get_party_account(party_type, party, company=None): if not company: frappe.throw(_("Please select a Company")) - if not party: - return + if not party and party_type in ['Customer', 'Supplier']: + default_account_name = "default_receivable_account" \ + if party_type=="Customer" else "default_payable_account" + + return frappe.get_cached_value('Company', company, default_account_name) account = frappe.db.get_value("Party Account", {"parenttype": party_type, "parent": party, "company": company}, "account") @@ -509,7 +511,7 @@ def get_timeline_data(doctype, name): timeline_items = dict(data) - for date, count in iteritems(timeline_items): + for date, count in timeline_items.items(): timestamp = get_timestamp(date) out.update({ timestamp: count }) diff --git a/erpnext/buying/doctype/supplier_item_group/__init__.py b/erpnext/accounts/print_format_field_template/__init__.py similarity index 100% rename from erpnext/buying/doctype/supplier_item_group/__init__.py rename to erpnext/accounts/print_format_field_template/__init__.py diff --git a/erpnext/healthcare/__init__.py b/erpnext/accounts/print_format_field_template/purchase_invoice_taxes/__init__.py similarity index 100% rename from erpnext/healthcare/__init__.py rename to erpnext/accounts/print_format_field_template/purchase_invoice_taxes/__init__.py diff --git a/erpnext/accounts/print_format_field_template/purchase_invoice_taxes/purchase_invoice_taxes.json b/erpnext/accounts/print_format_field_template/purchase_invoice_taxes/purchase_invoice_taxes.json new file mode 100644 index 00000000000..f525f7b8d42 --- /dev/null +++ b/erpnext/accounts/print_format_field_template/purchase_invoice_taxes/purchase_invoice_taxes.json @@ -0,0 +1,16 @@ +{ + "creation": "2021-10-19 18:06:53.083133", + "docstatus": 0, + "doctype": "Print Format Field Template", + "document_type": "Purchase Invoice", + "field": "taxes", + "idx": 0, + "modified": "2021-10-19 18:06:53.083133", + "modified_by": "Administrator", + "module": "Accounts", + "name": "Purchase Invoice Taxes", + "owner": "Administrator", + "standard": 1, + "template": "", + "template_file": "templates/print_formats/includes/taxes_and_charges.html" +} \ No newline at end of file diff --git a/erpnext/healthcare/dashboard_chart_source/__init__.py b/erpnext/accounts/print_format_field_template/sales_invoice_taxes/__init__.py similarity index 100% rename from erpnext/healthcare/dashboard_chart_source/__init__.py rename to erpnext/accounts/print_format_field_template/sales_invoice_taxes/__init__.py diff --git a/erpnext/accounts/print_format_field_template/sales_invoice_taxes/sales_invoice_taxes.json b/erpnext/accounts/print_format_field_template/sales_invoice_taxes/sales_invoice_taxes.json new file mode 100644 index 00000000000..8ce62a8b26f --- /dev/null +++ b/erpnext/accounts/print_format_field_template/sales_invoice_taxes/sales_invoice_taxes.json @@ -0,0 +1,16 @@ +{ + "creation": "2021-10-19 17:50:00.152759", + "docstatus": 0, + "doctype": "Print Format Field Template", + "document_type": "Sales Invoice", + "field": "taxes", + "idx": 0, + "modified": "2021-10-19 18:13:20.894207", + "modified_by": "Administrator", + "module": "Accounts", + "name": "Sales Invoice Taxes", + "owner": "Administrator", + "standard": 1, + "template": "", + "template_file": "templates/print_formats/includes/taxes_and_charges.html" +} \ No newline at end of file diff --git a/erpnext/accounts/report/account_balance/account_balance.py b/erpnext/accounts/report/account_balance/account_balance.py index 9ae61ddcfd2..a2c70a45f99 100644 --- a/erpnext/accounts/report/account_balance/account_balance.py +++ b/erpnext/accounts/report/account_balance/account_balance.py @@ -1,7 +1,6 @@ # Copyright (c) 2013, Frappe Technologies Pvt. Ltd. and contributors # For license information, please see license.txt -from __future__ import unicode_literals import frappe from frappe import _ diff --git a/erpnext/accounts/report/account_balance/test_account_balance.py b/erpnext/accounts/report/account_balance/test_account_balance.py index 94c73f5264b..73370e4ed6f 100644 --- a/erpnext/accounts/report/account_balance/test_account_balance.py +++ b/erpnext/accounts/report/account_balance/test_account_balance.py @@ -1,5 +1,3 @@ -from __future__ import unicode_literals - import unittest import frappe diff --git a/erpnext/accounts/report/accounts_payable/accounts_payable.js b/erpnext/accounts/report/accounts_payable/accounts_payable.js index b6c6689be0b..81c60bb337d 100644 --- a/erpnext/accounts/report/accounts_payable/accounts_payable.js +++ b/erpnext/accounts/report/accounts_payable/accounts_payable.js @@ -4,7 +4,7 @@ frappe.query_reports["Accounts Payable"] = { "filters": [ { - "fieldname":"company", + "fieldname": "company", "label": __("Company"), "fieldtype": "Link", "options": "Company", @@ -12,19 +12,19 @@ frappe.query_reports["Accounts Payable"] = { "default": frappe.defaults.get_user_default("Company") }, { - "fieldname":"report_date", + "fieldname": "report_date", "label": __("Posting Date"), "fieldtype": "Date", "default": frappe.datetime.get_today() }, { - "fieldname":"finance_book", + "fieldname": "finance_book", "label": __("Finance Book"), "fieldtype": "Link", "options": "Finance Book" }, { - "fieldname":"cost_center", + "fieldname": "cost_center", "label": __("Cost Center"), "fieldtype": "Link", "options": "Cost Center", @@ -38,7 +38,7 @@ frappe.query_reports["Accounts Payable"] = { } }, { - "fieldname":"supplier", + "fieldname": "supplier", "label": __("Supplier"), "fieldtype": "Link", "options": "Supplier", @@ -54,48 +54,48 @@ frappe.query_reports["Accounts Payable"] = { } }, { - "fieldname":"ageing_based_on", + "fieldname": "ageing_based_on", "label": __("Ageing Based On"), "fieldtype": "Select", "options": 'Posting Date\nDue Date\nSupplier Invoice Date', "default": "Due Date" }, { - "fieldname":"range1", + "fieldname": "range1", "label": __("Ageing Range 1"), "fieldtype": "Int", "default": "30", "reqd": 1 }, { - "fieldname":"range2", + "fieldname": "range2", "label": __("Ageing Range 2"), "fieldtype": "Int", "default": "60", "reqd": 1 }, { - "fieldname":"range3", + "fieldname": "range3", "label": __("Ageing Range 3"), "fieldtype": "Int", "default": "90", "reqd": 1 }, { - "fieldname":"range4", + "fieldname": "range4", "label": __("Ageing Range 4"), "fieldtype": "Int", "default": "120", "reqd": 1 }, { - "fieldname":"payment_terms_template", + "fieldname": "payment_terms_template", "label": __("Payment Terms Template"), "fieldtype": "Link", "options": "Payment Terms Template" }, { - "fieldname":"supplier_group", + "fieldname": "supplier_group", "label": __("Supplier Group"), "fieldtype": "Link", "options": "Supplier Group" @@ -106,12 +106,17 @@ frappe.query_reports["Accounts Payable"] = { "fieldtype": "Check" }, { - "fieldname":"based_on_payment_terms", + "fieldname": "based_on_payment_terms", "label": __("Based On Payment Terms"), "fieldtype": "Check", }, { - "fieldname":"tax_id", + "fieldname": "show_remarks", + "label": __("Show Remarks"), + "fieldtype": "Check", + }, + { + "fieldname": "tax_id", "label": __("Tax Id"), "fieldtype": "Data", "hidden": 1 diff --git a/erpnext/accounts/report/accounts_payable/accounts_payable.py b/erpnext/accounts/report/accounts_payable/accounts_payable.py index 0de573e4541..7b199949113 100644 --- a/erpnext/accounts/report/accounts_payable/accounts_payable.py +++ b/erpnext/accounts/report/accounts_payable/accounts_payable.py @@ -1,7 +1,6 @@ # Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors # License: GNU General Public License v3. See license.txt -from __future__ import unicode_literals from erpnext.accounts.report.accounts_receivable.accounts_receivable import ReceivablePayableReport diff --git a/erpnext/accounts/report/accounts_payable_summary/accounts_payable_summary.py b/erpnext/accounts/report/accounts_payable_summary/accounts_payable_summary.py index 6034ec0d83b..65fe1de5689 100644 --- a/erpnext/accounts/report/accounts_payable_summary/accounts_payable_summary.py +++ b/erpnext/accounts/report/accounts_payable_summary/accounts_payable_summary.py @@ -1,7 +1,6 @@ # Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors # License: GNU General Public License v3. See license.txt -from __future__ import unicode_literals from erpnext.accounts.report.accounts_receivable_summary.accounts_receivable_summary import ( AccountsReceivableSummary, diff --git a/erpnext/accounts/report/accounts_receivable/accounts_receivable.js b/erpnext/accounts/report/accounts_receivable/accounts_receivable.js index 1a32e2a8e06..570029851e8 100644 --- a/erpnext/accounts/report/accounts_receivable/accounts_receivable.js +++ b/erpnext/accounts/report/accounts_receivable/accounts_receivable.js @@ -4,7 +4,7 @@ frappe.query_reports["Accounts Receivable"] = { "filters": [ { - "fieldname":"company", + "fieldname": "company", "label": __("Company"), "fieldtype": "Link", "options": "Company", @@ -12,19 +12,19 @@ frappe.query_reports["Accounts Receivable"] = { "default": frappe.defaults.get_user_default("Company") }, { - "fieldname":"report_date", + "fieldname": "report_date", "label": __("Posting Date"), "fieldtype": "Date", "default": frappe.datetime.get_today() }, { - "fieldname":"finance_book", + "fieldname": "finance_book", "label": __("Finance Book"), "fieldtype": "Link", "options": "Finance Book" }, { - "fieldname":"cost_center", + "fieldname": "cost_center", "label": __("Cost Center"), "fieldtype": "Link", "options": "Cost Center", @@ -38,7 +38,7 @@ frappe.query_reports["Accounts Receivable"] = { } }, { - "fieldname":"customer", + "fieldname": "customer", "label": __("Customer"), "fieldtype": "Link", "options": "Customer", @@ -67,66 +67,66 @@ frappe.query_reports["Accounts Receivable"] = { } }, { - "fieldname":"ageing_based_on", + "fieldname": "ageing_based_on", "label": __("Ageing Based On"), "fieldtype": "Select", "options": 'Posting Date\nDue Date', "default": "Due Date" }, { - "fieldname":"range1", + "fieldname": "range1", "label": __("Ageing Range 1"), "fieldtype": "Int", "default": "30", "reqd": 1 }, { - "fieldname":"range2", + "fieldname": "range2", "label": __("Ageing Range 2"), "fieldtype": "Int", "default": "60", "reqd": 1 }, { - "fieldname":"range3", + "fieldname": "range3", "label": __("Ageing Range 3"), "fieldtype": "Int", "default": "90", "reqd": 1 }, { - "fieldname":"range4", + "fieldname": "range4", "label": __("Ageing Range 4"), "fieldtype": "Int", "default": "120", "reqd": 1 }, { - "fieldname":"customer_group", + "fieldname": "customer_group", "label": __("Customer Group"), "fieldtype": "Link", "options": "Customer Group" }, { - "fieldname":"payment_terms_template", + "fieldname": "payment_terms_template", "label": __("Payment Terms Template"), "fieldtype": "Link", "options": "Payment Terms Template" }, { - "fieldname":"sales_partner", + "fieldname": "sales_partner", "label": __("Sales Partner"), "fieldtype": "Link", "options": "Sales Partner" }, { - "fieldname":"sales_person", + "fieldname": "sales_person", "label": __("Sales Person"), "fieldtype": "Link", "options": "Sales Person" }, { - "fieldname":"territory", + "fieldname": "territory", "label": __("Territory"), "fieldtype": "Link", "options": "Territory" @@ -137,45 +137,50 @@ frappe.query_reports["Accounts Receivable"] = { "fieldtype": "Check" }, { - "fieldname":"based_on_payment_terms", + "fieldname": "based_on_payment_terms", "label": __("Based On Payment Terms"), "fieldtype": "Check", }, { - "fieldname":"show_future_payments", + "fieldname": "show_future_payments", "label": __("Show Future Payments"), "fieldtype": "Check", }, { - "fieldname":"show_delivery_notes", + "fieldname": "show_delivery_notes", "label": __("Show Linked Delivery Notes"), "fieldtype": "Check", }, { - "fieldname":"show_sales_person", + "fieldname": "show_sales_person", "label": __("Show Sales Person"), "fieldtype": "Check", }, { - "fieldname":"tax_id", + "fieldname": "show_remarks", + "label": __("Show Remarks"), + "fieldtype": "Check", + }, + { + "fieldname": "tax_id", "label": __("Tax Id"), "fieldtype": "Data", "hidden": 1 }, { - "fieldname":"customer_name", + "fieldname": "customer_name", "label": __("Customer Name"), "fieldtype": "Data", "hidden": 1 }, { - "fieldname":"payment_terms", + "fieldname": "payment_terms", "label": __("Payment Tems"), "fieldtype": "Data", "hidden": 1 }, { - "fieldname":"credit_limit", + "fieldname": "credit_limit", "label": __("Credit Limit"), "fieldtype": "Currency", "hidden": 1 diff --git a/erpnext/accounts/report/accounts_receivable/accounts_receivable.py b/erpnext/accounts/report/accounts_receivable/accounts_receivable.py index e91fdf27cdd..88bcdad7102 100755 --- a/erpnext/accounts/report/accounts_receivable/accounts_receivable.py +++ b/erpnext/accounts/report/accounts_receivable/accounts_receivable.py @@ -1,7 +1,6 @@ # Copyright (c) 2015, Frappe Technologies Pvt. Ltd. # License: GNU General Public License v3. See license.txt -from __future__ import unicode_literals from collections import OrderedDict @@ -106,6 +105,7 @@ class ReceivablePayableReport(object): party = gle.party, posting_date = gle.posting_date, account_currency = gle.account_currency, + remarks = gle.remarks if self.filters.get("show_remarks") else None, invoiced = 0.0, paid = 0.0, credit_note = 0.0, @@ -583,10 +583,12 @@ class ReceivablePayableReport(object): else: select_fields = "debit, credit" + remarks = ", remarks" if self.filters.get("show_remarks") else "" + self.gl_entries = frappe.db.sql(""" select name, posting_date, account, party_type, party, voucher_type, voucher_no, cost_center, - against_voucher_type, against_voucher, account_currency, {0} + against_voucher_type, against_voucher, account_currency, {0} {remarks} from `tabGL Entry` where @@ -595,7 +597,7 @@ class ReceivablePayableReport(object): and party_type=%s and (party is not null and party != '') {1} {2} {3}""" - .format(select_fields, date_condition, conditions, order_by), values, as_dict=True) + .format(select_fields, date_condition, conditions, order_by, remarks=remarks), values, as_dict=True) def get_sales_invoices_or_customers_based_on_sales_person(self): if self.filters.get("sales_person"): @@ -754,6 +756,10 @@ class ReceivablePayableReport(object): self.add_column(label=_('Voucher Type'), fieldname='voucher_type', fieldtype='Data') self.add_column(label=_('Voucher No'), fieldname='voucher_no', fieldtype='Dynamic Link', options='voucher_type', width=180) + + if self.filters.show_remarks: + self.add_column(label=_('Remarks'), fieldname='remarks', fieldtype='Text', width=200), + self.add_column(label='Due Date', fieldtype='Date') if self.party_type == "Supplier": diff --git a/erpnext/accounts/report/accounts_receivable/test_accounts_receivable.py b/erpnext/accounts/report/accounts_receivable/test_accounts_receivable.py index 1d24561bb3f..ab95c93e368 100644 --- a/erpnext/accounts/report/accounts_receivable/test_accounts_receivable.py +++ b/erpnext/accounts/report/accounts_receivable/test_accounts_receivable.py @@ -1,5 +1,3 @@ -from __future__ import unicode_literals - import unittest import frappe diff --git a/erpnext/accounts/report/accounts_receivable_summary/accounts_receivable_summary.py b/erpnext/accounts/report/accounts_receivable_summary/accounts_receivable_summary.py index 106f224a740..3c94629203e 100644 --- a/erpnext/accounts/report/accounts_receivable_summary/accounts_receivable_summary.py +++ b/erpnext/accounts/report/accounts_receivable_summary/accounts_receivable_summary.py @@ -1,12 +1,10 @@ # Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors and contributors # For license information, please see license.txt -from __future__ import unicode_literals import frappe from frappe import _, scrub from frappe.utils import cint -from six import iteritems from erpnext.accounts.party import get_partywise_advanced_payment_amount from erpnext.accounts.report.accounts_receivable.accounts_receivable import ReceivablePayableReport @@ -38,7 +36,7 @@ class AccountsReceivableSummary(ReceivablePayableReport): party_advance_amount = get_partywise_advanced_payment_amount(self.party_type, self.filters.report_date, self.filters.show_future_payments, self.filters.company) or {} - for party, party_dict in iteritems(self.party_total): + for party, party_dict in self.party_total.items(): if party_dict.outstanding == 0: continue diff --git a/erpnext/accounts/report/asset_depreciation_ledger/asset_depreciation_ledger.py b/erpnext/accounts/report/asset_depreciation_ledger/asset_depreciation_ledger.py index 0fd4ca0f24a..98f5b74eaac 100644 --- a/erpnext/accounts/report/asset_depreciation_ledger/asset_depreciation_ledger.py +++ b/erpnext/accounts/report/asset_depreciation_ledger/asset_depreciation_ledger.py @@ -1,7 +1,6 @@ # Copyright (c) 2013, Frappe Technologies Pvt. Ltd. and contributors # For license information, please see license.txt -from __future__ import unicode_literals import frappe from frappe import _ diff --git a/erpnext/accounts/report/asset_depreciations_and_balances/asset_depreciations_and_balances.py b/erpnext/accounts/report/asset_depreciations_and_balances/asset_depreciations_and_balances.py index d34bc854bba..0f9435f4a57 100644 --- a/erpnext/accounts/report/asset_depreciations_and_balances/asset_depreciations_and_balances.py +++ b/erpnext/accounts/report/asset_depreciations_and_balances/asset_depreciations_and_balances.py @@ -1,7 +1,6 @@ # Copyright (c) 2013, Frappe Technologies Pvt. Ltd. and contributors # For license information, please see license.txt -from __future__ import unicode_literals import frappe from frappe import _ diff --git a/erpnext/accounts/report/balance_sheet/balance_sheet.py b/erpnext/accounts/report/balance_sheet/balance_sheet.py index 78ee7cab9af..dc1f7aae42e 100644 --- a/erpnext/accounts/report/balance_sheet/balance_sheet.py +++ b/erpnext/accounts/report/balance_sheet/balance_sheet.py @@ -1,7 +1,6 @@ # Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors # License: GNU General Public License v3. See license.txt -from __future__ import unicode_literals import frappe from frappe import _ diff --git a/erpnext/accounts/report/bank_clearance_summary/bank_clearance_summary.py b/erpnext/accounts/report/bank_clearance_summary/bank_clearance_summary.py index 1a1fa964fe0..b456e89f344 100644 --- a/erpnext/accounts/report/bank_clearance_summary/bank_clearance_summary.py +++ b/erpnext/accounts/report/bank_clearance_summary/bank_clearance_summary.py @@ -1,7 +1,6 @@ # Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors # License: GNU General Public License v3. See license.txt -from __future__ import unicode_literals import frappe from frappe import _ diff --git a/erpnext/accounts/report/bank_reconciliation_statement/bank_reconciliation_statement.py b/erpnext/accounts/report/bank_reconciliation_statement/bank_reconciliation_statement.py index b9843068a18..6c401fb8f3b 100644 --- a/erpnext/accounts/report/bank_reconciliation_statement/bank_reconciliation_statement.py +++ b/erpnext/accounts/report/bank_reconciliation_statement/bank_reconciliation_statement.py @@ -1,7 +1,6 @@ # Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors # License: GNU General Public License v3. See license.txt -from __future__ import unicode_literals import frappe from frappe import _ diff --git a/erpnext/accounts/report/billed_items_to_be_received/billed_items_to_be_received.py b/erpnext/accounts/report/billed_items_to_be_received/billed_items_to_be_received.py index 6c4cd671b24..1d7463c8920 100644 --- a/erpnext/accounts/report/billed_items_to_be_received/billed_items_to_be_received.py +++ b/erpnext/accounts/report/billed_items_to_be_received/billed_items_to_be_received.py @@ -1,7 +1,6 @@ # Copyright (c) 2013, Frappe Technologies Pvt. Ltd. and contributors # For license information, please see license.txt -from __future__ import unicode_literals import frappe from frappe import _ diff --git a/erpnext/accounts/report/budget_variance_report/budget_variance_report.py b/erpnext/accounts/report/budget_variance_report/budget_variance_report.py index c204250377f..3bb590a564d 100644 --- a/erpnext/accounts/report/budget_variance_report/budget_variance_report.py +++ b/erpnext/accounts/report/budget_variance_report/budget_variance_report.py @@ -1,14 +1,12 @@ # Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors # License: GNU General Public License v3. See license.txt -from __future__ import unicode_literals import datetime import frappe from frappe import _ from frappe.utils import flt, formatdate -from six import iteritems from erpnext.controllers.trends import get_period_date_ranges, get_period_month_ranges @@ -49,7 +47,7 @@ def execute(filters=None): return columns, data, None, chart def get_final_data(dimension, dimension_items, filters, period_month_ranges, data, DCC_allocation): - for account, monthwise_data in iteritems(dimension_items): + for account, monthwise_data in dimension_items.items(): row = [dimension, account] totals = [0, 0, 0] for year in get_fiscal_years(filters): diff --git a/erpnext/accounts/report/cash_flow/cash_flow.py b/erpnext/accounts/report/cash_flow/cash_flow.py index d5271885b7e..15041f2516e 100644 --- a/erpnext/accounts/report/cash_flow/cash_flow.py +++ b/erpnext/accounts/report/cash_flow/cash_flow.py @@ -1,12 +1,10 @@ # Copyright (c) 2013, Frappe Technologies Pvt. Ltd. and contributors # For license information, please see license.txt -from __future__ import unicode_literals import frappe from frappe import _ from frappe.utils import cint, cstr -from six import iteritems from erpnext.accounts.report.financial_statements import ( get_columns, @@ -139,9 +137,9 @@ def get_account_type_based_data(company, account_type, period_list, accumulated_ data["total"] = total return data -def get_account_type_based_gl_data(company, start_date, end_date, account_type, filters={}): +def get_account_type_based_gl_data(company, start_date, end_date, account_type, filters=None): cond = "" - filters = frappe._dict(filters) + filters = frappe._dict(filters or {}) if filters.include_default_book_entries: company_fb = frappe.db.get_value("Company", company, 'default_finance_book') @@ -202,7 +200,7 @@ def add_total_row_account(out, data, label, period_list, currency, summary_data, def get_report_summary(summary_data, currency): report_summary = [] - for label, value in iteritems(summary_data): + for label, value in summary_data.items(): report_summary.append( { "value": value, diff --git a/erpnext/accounts/report/cash_flow/custom_cash_flow.py b/erpnext/accounts/report/cash_flow/custom_cash_flow.py index bbc020e591f..45d147e7a21 100644 --- a/erpnext/accounts/report/cash_flow/custom_cash_flow.py +++ b/erpnext/accounts/report/cash_flow/custom_cash_flow.py @@ -1,7 +1,6 @@ # Copyright (c) 2018, Frappe Technologies Pvt. Ltd. and contributors # For license information, please see license.txt -from __future__ import unicode_literals import frappe from frappe import _ diff --git a/erpnext/accounts/report/consolidated_financial_statement/consolidated_financial_statement.js b/erpnext/accounts/report/consolidated_financial_statement/consolidated_financial_statement.js index 6a8301a6f91..e24a5f99184 100644 --- a/erpnext/accounts/report/consolidated_financial_statement/consolidated_financial_statement.js +++ b/erpnext/accounts/report/consolidated_financial_statement/consolidated_financial_statement.js @@ -103,8 +103,11 @@ frappe.require("assets/erpnext/js/financial_statements.js", function() { column.is_tree = true; } - value = default_formatter(value, row, column, data); + if (data && data.account && column.apply_currency_formatter) { + data.currency = erpnext.get_currency(column.company_name); + } + value = default_formatter(value, row, column, data); if (!data.parent_account) { value = $(`${value}`); diff --git a/erpnext/accounts/report/consolidated_financial_statement/consolidated_financial_statement.py b/erpnext/accounts/report/consolidated_financial_statement/consolidated_financial_statement.py index e419727c2d1..c71bc17ca79 100644 --- a/erpnext/accounts/report/consolidated_financial_statement/consolidated_financial_statement.py +++ b/erpnext/accounts/report/consolidated_financial_statement/consolidated_financial_statement.py @@ -1,14 +1,15 @@ # Copyright (c) 2013, Frappe Technologies Pvt. Ltd. and contributors # For license information, please see license.txt -from __future__ import unicode_literals + +from collections import defaultdict import frappe from frappe import _ from frappe.utils import cint, flt, getdate +import erpnext from erpnext.accounts.report.balance_sheet.balance_sheet import ( - check_opening_balance, get_chart_data, get_provisional_profit_loss, ) @@ -31,7 +32,7 @@ from erpnext.accounts.report.profit_and_loss_statement.profit_and_loss_statement from erpnext.accounts.report.profit_and_loss_statement.profit_and_loss_statement import ( get_report_summary as get_pl_summary, ) -from erpnext.accounts.report.utils import convert_to_presentation_currency +from erpnext.accounts.report.utils import convert, convert_to_presentation_currency def execute(filters=None): @@ -42,7 +43,7 @@ def execute(filters=None): fiscal_year = get_fiscal_year_data(filters.get('from_fiscal_year'), filters.get('to_fiscal_year')) companies_column, companies = get_companies(filters) - columns = get_columns(companies_column) + columns = get_columns(companies_column, filters) if filters.get('report') == "Balance Sheet": data, message, chart, report_summary = get_balance_sheet_data(fiscal_year, companies, columns, filters) @@ -73,21 +74,24 @@ def get_balance_sheet_data(fiscal_year, companies, columns, filters): provisional_profit_loss, total_credit = get_provisional_profit_loss(asset, liability, equity, companies, filters.get('company'), company_currency, True) - message, opening_balance = check_opening_balance(asset, liability, equity) + message, opening_balance = prepare_companywise_opening_balance(asset, liability, equity, companies) - if opening_balance and round(opening_balance,2) !=0: - unclosed ={ + if opening_balance: + unclosed = { "account_name": "'" + _("Unclosed Fiscal Years Profit / Loss (Credit)") + "'", "account": "'" + _("Unclosed Fiscal Years Profit / Loss (Credit)") + "'", "warn_if_negative": True, "currency": company_currency } - for company in companies: - unclosed[company] = opening_balance - if provisional_profit_loss: - provisional_profit_loss[company] = provisional_profit_loss[company] - opening_balance - unclosed["total"]=opening_balance + for company in companies: + unclosed[company] = opening_balance.get(company) + if provisional_profit_loss and provisional_profit_loss.get(company): + provisional_profit_loss[company] = ( + flt(provisional_profit_loss[company]) - flt(opening_balance.get(company)) + ) + + unclosed["total"] = opening_balance.get(company) data.append(unclosed) if provisional_profit_loss: @@ -102,6 +106,38 @@ def get_balance_sheet_data(fiscal_year, companies, columns, filters): return data, message, chart, report_summary +def prepare_companywise_opening_balance(asset_data, liability_data, equity_data, companies): + opening_balance = {} + for company in companies: + opening_value = 0 + + # opening_value = Aseet - liability - equity + for data in [asset_data, liability_data, equity_data]: + if data: + account_name = get_root_account_name(data[0].root_type, company) + opening_value += (get_opening_balance(account_name, data, company) or 0.0) + + opening_balance[company] = opening_value + + if opening_balance: + return _("Previous Financial Year is not closed"), opening_balance + + return '', {} + +def get_opening_balance(account_name, data, company): + for row in data: + if row.get('account_name') == account_name: + return row.get('company_wise_opening_bal', {}).get(company, 0.0) + +def get_root_account_name(root_type, company): + return frappe.get_all( + 'Account', + fields=['account_name'], + filters = {'root_type': root_type, 'is_group': 1, + 'company': company, 'parent_account': ('is', 'not set')}, + as_list=1 + )[0][0] + def get_profit_loss_data(fiscal_year, companies, columns, filters): income, expense, net_profit_loss = get_income_expense_data(companies, fiscal_year, filters) company_currency = get_company_currency(filters) @@ -193,30 +229,37 @@ def get_account_type_based_data(account_type, companies, fiscal_year, filters): data["total"] = total return data -def get_columns(companies): - columns = [{ - "fieldname": "account", - "label": _("Account"), - "fieldtype": "Link", - "options": "Account", - "width": 300 - }] - - columns.append({ - "fieldname": "currency", - "label": _("Currency"), - "fieldtype": "Link", - "options": "Currency", - "hidden": 1 - }) +def get_columns(companies, filters): + columns = [ + { + "fieldname": "account", + "label": _("Account"), + "fieldtype": "Link", + "options": "Account", + "width": 300 + }, { + "fieldname": "currency", + "label": _("Currency"), + "fieldtype": "Link", + "options": "Currency", + "hidden": 1 + } + ] for company in companies: + apply_currency_formatter = 1 if not filters.presentation_currency else 0 + currency = filters.presentation_currency + if not currency: + currency = erpnext.get_company_currency(company) + columns.append({ "fieldname": company, - "label": company, + "label": f'{company} ({currency})', "fieldtype": "Currency", "options": "currency", - "width": 150 + "width": 150, + "apply_currency_formatter": apply_currency_formatter, + "company_name": company }) return columns @@ -236,6 +279,8 @@ def get_data(companies, root_type, balance_must_be, fiscal_year, filters=None, i start_date = filters.period_start_date if filters.report != 'Balance Sheet' else None end_date = filters.period_end_date + filters.end_date = end_date + gl_entries_by_account = {} for root in frappe.db.sql("""select lft, rgt from tabAccount where root_type=%s and ifnull(parent_account, '') = ''""", root_type, as_dict=1): @@ -244,9 +289,10 @@ def get_data(companies, root_type, balance_must_be, fiscal_year, filters=None, i end_date, root.lft, root.rgt, filters, gl_entries_by_account, accounts_by_name, accounts, ignore_closing_entries=False) - calculate_values(accounts_by_name, gl_entries_by_account, companies, start_date, filters) + calculate_values(accounts_by_name, gl_entries_by_account, companies, filters, fiscal_year) accumulate_values_into_parents(accounts, accounts_by_name, companies) - out = prepare_data(accounts, start_date, end_date, balance_must_be, companies, company_currency) + + out = prepare_data(accounts, start_date, end_date, balance_must_be, companies, company_currency, filters) if out: add_total_row(out, root_type, balance_must_be, companies, company_currency) @@ -257,19 +303,44 @@ def get_company_currency(filters=None): return (filters.get('presentation_currency') or frappe.get_cached_value('Company', filters.company, "default_currency")) -def calculate_values(accounts_by_name, gl_entries_by_account, companies, start_date, filters): +def calculate_values(accounts_by_name, gl_entries_by_account, companies, filters, fiscal_year): + start_date = (fiscal_year.year_start_date + if filters.filter_based_on == 'Fiscal Year' else filters.period_start_date) + for entries in gl_entries_by_account.values(): for entry in entries: - d = accounts_by_name.get(entry.account_name) + if entry.account_number: + account_name = entry.account_number + ' - ' + entry.account_name + else: + account_name = entry.account_name + + d = accounts_by_name.get(account_name) + if d: + debit, credit = 0, 0 for company in companies: # check if posting date is within the period if (entry.company == company or (filters.get('accumulated_in_group_company')) and entry.company in companies.get(company)): - d[company] = d.get(company, 0.0) + flt(entry.debit) - flt(entry.credit) + parent_company_currency = erpnext.get_company_currency(d.company) + child_company_currency = erpnext.get_company_currency(entry.company) + + debit, credit = flt(entry.debit), flt(entry.credit) + + if (not filters.get('presentation_currency') + and entry.company != company + and parent_company_currency != child_company_currency + and filters.get('accumulated_in_group_company')): + debit = convert(debit, parent_company_currency, child_company_currency, filters.end_date) + credit = convert(credit, parent_company_currency, child_company_currency, filters.end_date) + + d[company] = d.get(company, 0.0) + flt(debit) - flt(credit) + + if entry.posting_date < getdate(start_date): + d['company_wise_opening_bal'][company] += (flt(debit) - flt(credit)) if entry.posting_date < getdate(start_date): - d["opening_balance"] = d.get("opening_balance", 0.0) + flt(entry.debit) - flt(entry.credit) + d["opening_balance"] = d.get("opening_balance", 0.0) + flt(debit) - flt(credit) def accumulate_values_into_parents(accounts, accounts_by_name, companies): """accumulate children's values in parent accounts""" @@ -277,17 +348,18 @@ def accumulate_values_into_parents(accounts, accounts_by_name, companies): if d.parent_account: account = d.parent_account_name - if not accounts_by_name.get(account): - continue + # if not accounts_by_name.get(account): + # continue for company in companies: accounts_by_name[account][company] = \ accounts_by_name[account].get(company, 0.0) + d.get(company, 0.0) + accounts_by_name[account]['company_wise_opening_bal'][company] += d.get('company_wise_opening_bal', {}).get(company, 0.0) + accounts_by_name[account]["opening_balance"] = \ accounts_by_name[account].get("opening_balance", 0.0) + d.get("opening_balance", 0.0) - def get_account_heads(root_type, companies, filters): accounts = get_accounts(root_type, filters) @@ -307,7 +379,14 @@ def update_parent_account_names(accounts): of account_number and suffix of company abbr. This function adds key called `parent_account_name` which does not have such prefix/suffix. """ - name_to_account_map = { d.name : d.account_name for d in accounts } + name_to_account_map = {} + + for d in accounts: + if d.account_number: + account_name = d.account_number + ' - ' + d.account_name + else: + account_name = d.account_name + name_to_account_map[d.name] = account_name for account in accounts: if account.parent_account: @@ -341,7 +420,7 @@ def get_accounts(root_type, filters): `tabAccount` where company = %s and root_type = %s """ , (filters.get('company'), root_type), as_dict=1) -def prepare_data(accounts, start_date, end_date, balance_must_be, companies, company_currency): +def prepare_data(accounts, start_date, end_date, balance_must_be, companies, company_currency, filters): data = [] for d in accounts: @@ -355,10 +434,13 @@ def prepare_data(accounts, start_date, end_date, balance_must_be, companies, com "parent_account": _(d.parent_account), "indent": flt(d.indent), "year_start_date": start_date, + "root_type": d.root_type, "year_end_date": end_date, - "currency": company_currency, + "currency": filters.presentation_currency, + "company_wise_opening_bal": d.company_wise_opening_bal, "opening_balance": d.get("opening_balance", 0.0) * (1 if balance_must_be == "Debit" else -1) }) + for company in companies: if d.get(company) and balance_must_be == "Credit": # change sign based on Debit or Credit, since calculation is done using (debit - credit) @@ -373,6 +455,7 @@ def prepare_data(accounts, start_date, end_date, balance_must_be, companies, com row["has_value"] = has_value row["total"] = total + data.append(row) return data @@ -420,7 +503,11 @@ def set_gl_entries_by_account(from_date, to_date, root_lft, root_rgt, filters, g convert_to_presentation_currency(gl_entries, currency_info, filters.get('company')) for entry in gl_entries: - account_name = entry.account_name + if entry.account_number: + account_name = entry.account_number + ' - ' + entry.account_name + else: + account_name = entry.account_name + validate_entries(account_name, entry, accounts_by_name, accounts) gl_entries_by_account.setdefault(account_name, []).append(entry) @@ -431,6 +518,7 @@ def get_account_details(account): 'is_group', 'account_name', 'account_number', 'parent_account', 'lft', 'rgt'], as_dict=1) def validate_entries(key, entry, accounts_by_name, accounts): + # If an account present in the child company and not in the parent company if key not in accounts_by_name: args = get_account_details(entry.account) @@ -440,12 +528,23 @@ def validate_entries(key, entry, accounts_by_name, accounts): args.update({ 'lft': parent_args.lft + 1, 'rgt': parent_args.rgt - 1, + 'indent': 3, 'root_type': parent_args.root_type, - 'report_type': parent_args.report_type + 'report_type': parent_args.report_type, + 'parent_account_name': parent_args.account_name, + 'company_wise_opening_bal': defaultdict(float) }) accounts_by_name.setdefault(key, args) - accounts.append(args) + + idx = len(accounts) + # To identify parent account index + for index, row in enumerate(accounts): + if row.parent_account_name == args.parent_account_name: + idx = index + break + + accounts.insert(idx+1, args) def get_additional_conditions(from_date, ignore_closing_entries, filters): additional_conditions = [] @@ -475,7 +574,6 @@ def add_total_row(out, root_type, balance_must_be, companies, company_currency): for company in companies: total_row.setdefault(company, 0.0) total_row[company] += row.get(company, 0.0) - row[company] = 0.0 total_row.setdefault("total", 0.0) total_row["total"] += flt(row["total"]) @@ -491,7 +589,13 @@ def filter_accounts(accounts, depth=10): parent_children_map = {} accounts_by_name = {} for d in accounts: - accounts_by_name[d.account_name] = d + if d.account_number: + account_name = d.account_number + ' - ' + d.account_name + else: + account_name = d.account_name + d['company_wise_opening_bal'] = defaultdict(float) + accounts_by_name[account_name] = d + parent_children_map.setdefault(d.parent_account or None, []).append(d) filtered_accounts = [] diff --git a/erpnext/accounts/report/customer_ledger_summary/customer_ledger_summary.py b/erpnext/accounts/report/customer_ledger_summary/customer_ledger_summary.py index 603fbac5aa9..56db841e94d 100644 --- a/erpnext/accounts/report/customer_ledger_summary/customer_ledger_summary.py +++ b/erpnext/accounts/report/customer_ledger_summary/customer_ledger_summary.py @@ -1,12 +1,10 @@ # Copyright (c) 2013, Frappe Technologies Pvt. Ltd. and contributors # For license information, please see license.txt -from __future__ import unicode_literals import frappe from frappe import _, scrub from frappe.utils import getdate, nowdate -from six import iteritems, itervalues class PartyLedgerSummaryReport(object): @@ -144,9 +142,9 @@ class PartyLedgerSummaryReport(object): self.party_data[gle.party].paid_amount -= amount out = [] - for party, row in iteritems(self.party_data): + for party, row in self.party_data.items(): if row.opening_balance or row.invoiced_amount or row.paid_amount or row.return_amount or row.closing_amount: - total_party_adjustment = sum(amount for amount in itervalues(self.party_adjustment_details.get(party, {}))) + total_party_adjustment = sum(amount for amount in self.party_adjustment_details.get(party, {}).values()) row.paid_amount -= total_party_adjustment adjustments = self.party_adjustment_details.get(party, {}) @@ -268,7 +266,7 @@ class PartyLedgerSummaryReport(object): adjustment_voucher_entries.setdefault((gle.voucher_type, gle.voucher_no), []) adjustment_voucher_entries[(gle.voucher_type, gle.voucher_no)].append(gle) - for voucher_gl_entries in itervalues(adjustment_voucher_entries): + for voucher_gl_entries in adjustment_voucher_entries.values(): parties = {} accounts = {} has_irrelevant_entry = False @@ -288,7 +286,7 @@ class PartyLedgerSummaryReport(object): if parties and accounts: if len(parties) == 1: party = list(parties.keys())[0] - for account, amount in iteritems(accounts): + for account, amount in accounts.items(): self.party_adjustment_accounts.add(account) self.party_adjustment_details.setdefault(party, {}) self.party_adjustment_details[party].setdefault(account, 0) @@ -296,7 +294,7 @@ class PartyLedgerSummaryReport(object): elif len(accounts) == 1 and not has_irrelevant_entry: account = list(accounts.keys())[0] self.party_adjustment_accounts.add(account) - for party, amount in iteritems(parties): + for party, amount in parties.items(): self.party_adjustment_details.setdefault(party, {}) self.party_adjustment_details[party].setdefault(account, 0) self.party_adjustment_details[party][account] += amount diff --git a/erpnext/accounts/report/delivered_items_to_be_billed/delivered_items_to_be_billed.py b/erpnext/accounts/report/delivered_items_to_be_billed/delivered_items_to_be_billed.py index f096094296c..004d09250ab 100644 --- a/erpnext/accounts/report/delivered_items_to_be_billed/delivered_items_to_be_billed.py +++ b/erpnext/accounts/report/delivered_items_to_be_billed/delivered_items_to_be_billed.py @@ -1,7 +1,6 @@ # Copyright (c) 2013, Frappe Technologies Pvt. Ltd. and contributors # For license information, please see license.txt -from __future__ import unicode_literals from frappe import _ diff --git a/erpnext/accounts/report/dimension_wise_accounts_balance_report/dimension_wise_accounts_balance_report.py b/erpnext/accounts/report/dimension_wise_accounts_balance_report/dimension_wise_accounts_balance_report.py index 4212137d7a6..d547470bf3c 100644 --- a/erpnext/accounts/report/dimension_wise_accounts_balance_report/dimension_wise_accounts_balance_report.py +++ b/erpnext/accounts/report/dimension_wise_accounts_balance_report/dimension_wise_accounts_balance_report.py @@ -1,12 +1,10 @@ # Copyright (c) 2013, Frappe Technologies Pvt. Ltd. and contributors # For license information, please see license.txt -from __future__ import unicode_literals import frappe from frappe import _ from frappe.utils import cstr, flt -from six import itervalues import erpnext from erpnext.accounts.report.financial_statements import ( @@ -108,7 +106,7 @@ def set_gl_entries_by_account(dimension_items_list, filters, account, gl_entries def format_gl_entries(gl_entries_by_account, accounts_by_name, dimension_items_list): - for entries in itervalues(gl_entries_by_account): + for entries in gl_entries_by_account.values(): for entry in entries: d = accounts_by_name.get(entry.account) if not d: diff --git a/erpnext/accounts/report/financial_statements.py b/erpnext/accounts/report/financial_statements.py index 2cb8a6802a7..1e89b650c71 100644 --- a/erpnext/accounts/report/financial_statements.py +++ b/erpnext/accounts/report/financial_statements.py @@ -1,9 +1,6 @@ -# -*- coding: utf-8 -*- - # Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors # License: GNU General Public License v3. See license.txt -from __future__ import unicode_literals import functools import math @@ -12,8 +9,6 @@ import re import frappe from frappe import _ from frappe.utils import add_days, add_months, cint, cstr, flt, formatdate, get_first_day, getdate -from past.builtins import cmp -from six import itervalues from erpnext.accounts.doctype.accounting_dimension.accounting_dimension import ( get_accounting_dimensions, @@ -191,7 +186,7 @@ def get_appropriate_currency(company, filters=None): def calculate_values( accounts_by_name, gl_entries_by_account, period_list, accumulated_values, ignore_accumulated_values_for_fy): - for entries in itervalues(gl_entries_by_account): + for entries in gl_entries_by_account.values(): for entry in entries: d = accounts_by_name.get(entry.account) if not d: @@ -345,7 +340,7 @@ def sort_accounts(accounts, is_root=False, key="name"): def compare_accounts(a, b): if re.split(r'\W+', a[key])[0].isdigit(): # if chart of accounts is numbered, then sort by number - return cmp(a[key], b[key]) + return int(a[key] > b[key]) - int(a[key] < b[key]) elif is_root: if a.report_type != b.report_type and a.report_type == "Balance Sheet": return -1 @@ -357,7 +352,7 @@ def sort_accounts(accounts, is_root=False, key="name"): return -1 else: # sort by key (number) or name - return cmp(a[key], b[key]) + return int(a[key] > b[key]) - int(a[key] < b[key]) return 1 accounts.sort(key = functools.cmp_to_key(compare_accounts)) @@ -425,8 +420,7 @@ def set_gl_entries_by_account( {additional_conditions} and posting_date <= %(to_date)s and is_cancelled = 0 - {distributed_cost_center_query} - order by account, posting_date""".format( + {distributed_cost_center_query}""".format( additional_conditions=additional_conditions, distributed_cost_center_query=distributed_cost_center_query), gl_filters, as_dict=True) #nosec diff --git a/erpnext/accounts/report/general_ledger/general_ledger.js b/erpnext/accounts/report/general_ledger/general_ledger.js index 095f5eda66a..b2968761c63 100644 --- a/erpnext/accounts/report/general_ledger/general_ledger.js +++ b/erpnext/accounts/report/general_ledger/general_ledger.js @@ -110,9 +110,26 @@ frappe.query_reports["General Ledger"] = { "fieldname":"group_by", "label": __("Group by"), "fieldtype": "Select", - "options": ["", __("Group by Voucher"), __("Group by Voucher (Consolidated)"), - __("Group by Account"), __("Group by Party")], - "default": __("Group by Voucher (Consolidated)") + "options": [ + "", + { + label: __("Group by Voucher"), + value: "Group by Voucher", + }, + { + label: __("Group by Voucher (Consolidated)"), + value: "Group by Voucher (Consolidated)", + }, + { + label: __("Group by Account"), + value: "Group by Account", + }, + { + label: __("Group by Party"), + value: "Group by Party", + }, + ], + "default": "Group by Voucher (Consolidated)" }, { "fieldname":"tax_id", diff --git a/erpnext/accounts/report/general_ledger/general_ledger.py b/erpnext/accounts/report/general_ledger/general_ledger.py index a0445187499..385c8b2b6ed 100644 --- a/erpnext/accounts/report/general_ledger/general_ledger.py +++ b/erpnext/accounts/report/general_ledger/general_ledger.py @@ -1,14 +1,12 @@ # Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors # License: GNU General Public License v3. See license.txt -from __future__ import unicode_literals from collections import OrderedDict import frappe from frappe import _, _dict -from frappe.utils import cstr, flt, getdate -from six import iteritems +from frappe.utils import cstr, getdate from erpnext import get_company_currency, get_default_company from erpnext.accounts.doctype.accounting_dimension.accounting_dimension import ( @@ -19,6 +17,8 @@ from erpnext.accounts.report.financial_statements import get_cost_centers_with_c from erpnext.accounts.report.utils import convert_to_presentation_currency, get_currency from erpnext.accounts.utils import get_account_currency +# to cache translations +TRANSLATIONS = frappe._dict() def execute(filters=None): if not filters: @@ -44,10 +44,20 @@ def execute(filters=None): columns = get_columns(filters) + update_translations() + res = get_result(filters, account_details) return columns, res +def update_translations(): + TRANSLATIONS.update( + dict( + OPENING = _('Opening'), + TOTAL = _('Total'), + CLOSING_TOTAL = _('Closing (Opening + Total)') + ) + ) def validate_filters(filters, account_details): if not filters.get("company"): @@ -62,14 +72,14 @@ def validate_filters(filters, account_details): if not account_details.get(account): frappe.throw(_("Account {0} does not exists").format(account)) - if (filters.get("account") and filters.get("group_by") == _('Group by Account')): + if (filters.get("account") and filters.get("group_by") == 'Group by Account'): filters.account = frappe.parse_json(filters.get('account')) for account in filters.account: if account_details[account].is_group == 0: frappe.throw(_("Can not filter based on Child Account, if grouped by Account")) if (filters.get("voucher_no") - and filters.get("group_by") in [_('Group by Voucher')]): + and filters.get("group_by") in ['Group by Voucher']): frappe.throw(_("Can not filter based on Voucher No, if grouped by Voucher")) if filters.from_date > filters.to_date: @@ -153,8 +163,10 @@ def get_gl_entries(filters, accounting_dimensions): if filters.get("include_dimensions"): order_by_statement = "order by posting_date, creation" - if filters.get("group_by") == _("Group by Voucher"): + if filters.get("group_by") == "Group by Voucher": order_by_statement = "order by posting_date, voucher_type, voucher_no" + if filters.get("group_by") == "Group by Account": + order_by_statement = "order by account, posting_date, creation" if filters.get("include_default_book_entries"): filters['company_fb'] = frappe.db.get_value("Company", @@ -312,13 +324,13 @@ def get_data_with_opening_closing(filters, account_details, accounting_dimension # Opening for filtered account data.append(totals.opening) - if filters.get("group_by") != _('Group by Voucher (Consolidated)'): - for acc, acc_dict in iteritems(gle_map): + if filters.get("group_by") != 'Group by Voucher (Consolidated)': + for acc, acc_dict in gle_map.items(): # acc if acc_dict.entries: # opening data.append({}) - if filters.get("group_by") != _("Group by Voucher"): + if filters.get("group_by") != "Group by Voucher": data.append(acc_dict.totals.opening) data += acc_dict.entries @@ -327,7 +339,7 @@ def get_data_with_opening_closing(filters, account_details, accounting_dimension data.append(acc_dict.totals.total) # closing - if filters.get("group_by") != _("Group by Voucher"): + if filters.get("group_by") != "Group by Voucher": data.append(acc_dict.totals.closing) data.append({}) else: @@ -351,15 +363,15 @@ def get_totals_dict(): credit_in_account_currency=0.0 ) return _dict( - opening = _get_debit_credit_dict(_('Opening')), - total = _get_debit_credit_dict(_('Total')), - closing = _get_debit_credit_dict(_('Closing (Opening + Total)')) + opening = _get_debit_credit_dict(TRANSLATIONS.OPENING), + total = _get_debit_credit_dict(TRANSLATIONS.TOTAL), + closing = _get_debit_credit_dict(TRANSLATIONS.CLOSING_TOTAL) ) def group_by_field(group_by): - if group_by == _('Group by Party'): + if group_by == 'Group by Party': return 'party' - elif group_by in [_('Group by Voucher (Consolidated)'), _('Group by Account')]: + elif group_by in ['Group by Voucher (Consolidated)', 'Group by Account']: return 'account' else: return 'voucher_no' @@ -378,22 +390,23 @@ def get_accountwise_gle(filters, accounting_dimensions, gl_entries, gle_map): entries = [] consolidated_gle = OrderedDict() group_by = group_by_field(filters.get('group_by')) + group_by_voucher_consolidated = filters.get("group_by") == 'Group by Voucher (Consolidated)' if filters.get('show_net_values_in_party_account'): account_type_map = get_account_type_map(filters.get('company')) def update_value_in_dict(data, key, gle): - data[key].debit += flt(gle.debit) - data[key].credit += flt(gle.credit) + data[key].debit += gle.debit + data[key].credit += gle.credit - data[key].debit_in_account_currency += flt(gle.debit_in_account_currency) - data[key].credit_in_account_currency += flt(gle.credit_in_account_currency) + data[key].debit_in_account_currency += gle.debit_in_account_currency + data[key].credit_in_account_currency += gle.credit_in_account_currency if filters.get('show_net_values_in_party_account') and \ account_type_map.get(data[key].account) in ('Receivable', 'Payable'): - net_value = flt(data[key].debit) - flt(data[key].credit) - net_value_in_account_currency = flt(data[key].debit_in_account_currency) \ - - flt(data[key].credit_in_account_currency) + net_value = data[key].debit - data[key].credit + net_value_in_account_currency = data[key].debit_in_account_currency \ + - data[key].credit_in_account_currency if net_value < 0: dr_or_cr = 'credit' @@ -411,21 +424,29 @@ def get_accountwise_gle(filters, accounting_dimensions, gl_entries, gle_map): data[key].against_voucher += ', ' + gle.against_voucher from_date, to_date = getdate(filters.from_date), getdate(filters.to_date) - for gle in gl_entries: - if (gle.posting_date < from_date or - (cstr(gle.is_opening) == "Yes" and not filters.get("show_opening_entries"))): - update_value_in_dict(gle_map[gle.get(group_by)].totals, 'opening', gle) - update_value_in_dict(totals, 'opening', gle) + show_opening_entries = filters.get("show_opening_entries") - update_value_in_dict(gle_map[gle.get(group_by)].totals, 'closing', gle) + for gle in gl_entries: + group_by_value = gle.get(group_by) + + if (gle.posting_date < from_date or (cstr(gle.is_opening) == "Yes" and not show_opening_entries)): + if not group_by_voucher_consolidated: + update_value_in_dict(gle_map[group_by_value].totals, 'opening', gle) + update_value_in_dict(gle_map[group_by_value].totals, 'closing', gle) + + update_value_in_dict(totals, 'opening', gle) update_value_in_dict(totals, 'closing', gle) elif gle.posting_date <= to_date: - update_value_in_dict(gle_map[gle.get(group_by)].totals, 'total', gle) - update_value_in_dict(totals, 'total', gle) - if filters.get("group_by") != _('Group by Voucher (Consolidated)'): - gle_map[gle.get(group_by)].entries.append(gle) - elif filters.get("group_by") == _('Group by Voucher (Consolidated)'): + if not group_by_voucher_consolidated: + update_value_in_dict(gle_map[group_by_value].totals, 'total', gle) + update_value_in_dict(gle_map[group_by_value].totals, 'closing', gle) + update_value_in_dict(totals, 'total', gle) + update_value_in_dict(totals, 'closing', gle) + + gle_map[group_by_value].entries.append(gle) + + elif group_by_voucher_consolidated: keylist = [gle.get("voucher_type"), gle.get("voucher_no"), gle.get("account")] for dim in accounting_dimensions: keylist.append(gle.get(dim)) @@ -436,10 +457,9 @@ def get_accountwise_gle(filters, accounting_dimensions, gl_entries, gle_map): else: update_value_in_dict(consolidated_gle, key, gle) - update_value_in_dict(gle_map[gle.get(group_by)].totals, 'closing', gle) - update_value_in_dict(totals, 'closing', gle) - for key, value in consolidated_gle.items(): + update_value_in_dict(totals, 'total', value) + update_value_in_dict(totals, 'closing', value) entries.append(value) return totals, entries diff --git a/erpnext/accounts/report/gross_and_net_profit_report/gross_and_net_profit_report.py b/erpnext/accounts/report/gross_and_net_profit_report/gross_and_net_profit_report.py index 49522d9c873..b18b940fd2b 100644 --- a/erpnext/accounts/report/gross_and_net_profit_report/gross_and_net_profit_report.py +++ b/erpnext/accounts/report/gross_and_net_profit_report/gross_and_net_profit_report.py @@ -1,7 +1,6 @@ # Copyright (c) 2013, Frappe Technologies Pvt. Ltd. and contributors # For license information, please see license.txt -from __future__ import unicode_literals import copy diff --git a/erpnext/accounts/report/gross_profit/gross_profit.js b/erpnext/accounts/report/gross_profit/gross_profit.js index 856b97d1645..685f2d6176b 100644 --- a/erpnext/accounts/report/gross_profit/gross_profit.js +++ b/erpnext/accounts/report/gross_profit/gross_profit.js @@ -44,7 +44,7 @@ frappe.query_reports["Gross Profit"] = { "formatter": function(value, row, column, data, default_formatter) { value = default_formatter(value, row, column, data); - if (data && data.indent == 0.0) { + if (data && (data.indent == 0.0 || row[1].content == "Total")) { value = $(`${value}`); var $value = $(value).css("font-weight", "bold"); value = $value.wrap("

").parent().html(); diff --git a/erpnext/accounts/report/gross_profit/gross_profit.json b/erpnext/accounts/report/gross_profit/gross_profit.json index 5fff3fdba77..76c560ad247 100644 --- a/erpnext/accounts/report/gross_profit/gross_profit.json +++ b/erpnext/accounts/report/gross_profit/gross_profit.json @@ -9,7 +9,7 @@ "filters": [], "idx": 3, "is_standard": "Yes", - "modified": "2021-08-19 18:57:07.468202", + "modified": "2021-11-13 19:14:23.730198", "modified_by": "Administrator", "module": "Accounts", "name": "Gross Profit", diff --git a/erpnext/accounts/report/gross_profit/gross_profit.py b/erpnext/accounts/report/gross_profit/gross_profit.py index f08bca9ddaa..84effc0f467 100644 --- a/erpnext/accounts/report/gross_profit/gross_profit.py +++ b/erpnext/accounts/report/gross_profit/gross_profit.py @@ -1,7 +1,6 @@ # Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors # License: GNU General Public License v3. See license.txt -from __future__ import unicode_literals import frappe from frappe import _, scrub @@ -20,7 +19,7 @@ def execute(filters=None): data = [] group_wise_columns = frappe._dict({ - "invoice": ["parent", "customer", "customer_group", "posting_date","item_code", "item_name","item_group", "brand", "description", \ + "invoice": ["invoice_or_item", "customer", "customer_group", "posting_date","item_code", "item_name","item_group", "brand", "description", "warehouse", "qty", "base_rate", "buying_rate", "base_amount", "buying_amount", "gross_profit", "gross_profit_percent", "project"], "item_code": ["item_code", "item_name", "brand", "description", "qty", "base_rate", @@ -78,13 +77,15 @@ def get_data_when_not_grouped_by_invoice(gross_profit_data, filters, group_wise_ row.append(filters.currency) if idx == len(gross_profit_data.grouped_data)-1: - row[0] = frappe.bold("Total") + row[0] = "Total" + data.append(row) def get_columns(group_wise_columns, filters): columns = [] column_map = frappe._dict({ "parent": _("Sales Invoice") + ":Link/Sales Invoice:120", + "invoice_or_item": _("Sales Invoice") + ":Link/Sales Invoice:120", "posting_date": _("Posting Date") + ":Date:100", "posting_time": _("Posting Time") + ":Data:100", "item_code": _("Item Code") + ":Link/Item:100", @@ -123,7 +124,7 @@ def get_columns(group_wise_columns, filters): def get_column_names(): return frappe._dict({ - 'parent': 'sales_invoice', + 'invoice_or_item': 'sales_invoice', 'customer': 'customer', 'customer_group': 'customer_group', 'posting_date': 'posting_date', @@ -246,19 +247,28 @@ class GrossProfitGenerator(object): self.add_to_totals(new_row) else: for i, row in enumerate(self.grouped[key]): - if row.parent in self.returned_invoices \ - and row.item_code in self.returned_invoices[row.parent]: - returned_item_rows = self.returned_invoices[row.parent][row.item_code] - for returned_item_row in returned_item_rows: - row.qty += flt(returned_item_row.qty) - row.base_amount += flt(returned_item_row.base_amount, self.currency_precision) - row.buying_amount = flt(flt(row.qty) * flt(row.buying_rate), self.currency_precision) - if (flt(row.qty) or row.base_amount) and self.is_not_invoice_row(row): - row = self.set_average_rate(row) - self.grouped_data.append(row) - self.add_to_totals(row) + if row.indent == 1.0: + if row.parent in self.returned_invoices \ + and row.item_code in self.returned_invoices[row.parent]: + returned_item_rows = self.returned_invoices[row.parent][row.item_code] + for returned_item_row in returned_item_rows: + row.qty += flt(returned_item_row.qty) + row.base_amount += flt(returned_item_row.base_amount, self.currency_precision) + row.buying_amount = flt(flt(row.qty) * flt(row.buying_rate), self.currency_precision) + if (flt(row.qty) or row.base_amount): + row = self.set_average_rate(row) + self.grouped_data.append(row) + self.add_to_totals(row) + self.set_average_gross_profit(self.totals) - self.grouped_data.append(self.totals) + + if self.filters.get("group_by") == "Invoice": + self.totals.indent = 0.0 + self.totals.parent_invoice = "" + self.totals.invoice_or_item = "Total" + self.si_list.append(self.totals) + else: + self.grouped_data.append(self.totals) def is_not_invoice_row(self, row): return (self.filters.get("group_by") == "Invoice" and row.indent != 0.0) or self.filters.get("group_by") != "Invoice" @@ -447,7 +457,7 @@ class GrossProfitGenerator(object): if not row.indent: row.indent = 1.0 row.parent_invoice = row.parent - row.parent = row.item_code + row.invoice_or_item = row.item_code if frappe.db.exists('Product Bundle', row.item_code): self.add_bundle_items(row, index) @@ -456,7 +466,8 @@ class GrossProfitGenerator(object): return frappe._dict({ 'parent_invoice': "", 'indent': 0.0, - 'parent': row.parent, + 'invoice_or_item': row.parent, + 'parent': None, 'posting_date': row.posting_date, 'posting_time': row.posting_time, 'project': row.project, @@ -500,7 +511,8 @@ class GrossProfitGenerator(object): return frappe._dict({ 'parent_invoice': product_bundle.item_code, 'indent': product_bundle.indent + 1, - 'parent': item.item_code, + 'parent': None, + 'invoice_or_item': item.item_code, 'posting_date': product_bundle.posting_date, 'posting_time': product_bundle.posting_time, 'project': product_bundle.project, diff --git a/erpnext/accounts/report/inactive_sales_items/inactive_sales_items.py b/erpnext/accounts/report/inactive_sales_items/inactive_sales_items.py index 8f822711a7a..2f23c8ed1d6 100644 --- a/erpnext/accounts/report/inactive_sales_items/inactive_sales_items.py +++ b/erpnext/accounts/report/inactive_sales_items/inactive_sales_items.py @@ -1,7 +1,6 @@ # Copyright (c) 2013, Frappe Technologies Pvt. Ltd. and contributors # For license information, please see license.txt -from __future__ import unicode_literals import frappe from frappe import _ diff --git a/erpnext/accounts/report/item_wise_purchase_register/item_wise_purchase_register.py b/erpnext/accounts/report/item_wise_purchase_register/item_wise_purchase_register.py index cd25c050040..aaed58d070d 100644 --- a/erpnext/accounts/report/item_wise_purchase_register/item_wise_purchase_register.py +++ b/erpnext/accounts/report/item_wise_purchase_register/item_wise_purchase_register.py @@ -1,7 +1,6 @@ # Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors # License: GNU General Public License v3. See license.txt -from __future__ import unicode_literals import frappe from frappe import _ diff --git a/erpnext/accounts/report/item_wise_sales_register/item_wise_sales_register.py b/erpnext/accounts/report/item_wise_sales_register/item_wise_sales_register.py index 847a127d365..9b35538bb68 100644 --- a/erpnext/accounts/report/item_wise_sales_register/item_wise_sales_register.py +++ b/erpnext/accounts/report/item_wise_sales_register/item_wise_sales_register.py @@ -1,7 +1,6 @@ # Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors # License: GNU General Public License v3. See license.txt -from __future__ import unicode_literals import frappe from frappe import _ diff --git a/erpnext/accounts/report/non_billed_report.py b/erpnext/accounts/report/non_billed_report.py index b61f87df5bf..a421bc5c206 100644 --- a/erpnext/accounts/report/non_billed_report.py +++ b/erpnext/accounts/report/non_billed_report.py @@ -1,7 +1,6 @@ # Copyright (c) 2013, Frappe Technologies Pvt. Ltd. and contributors # For license information, please see license.txt -from __future__ import unicode_literals import frappe from frappe.model.meta import get_field_precision diff --git a/erpnext/accounts/report/payment_period_based_on_invoice_date/payment_period_based_on_invoice_date.py b/erpnext/accounts/report/payment_period_based_on_invoice_date/payment_period_based_on_invoice_date.py index 6c6af1cc5a2..6c12093763d 100644 --- a/erpnext/accounts/report/payment_period_based_on_invoice_date/payment_period_based_on_invoice_date.py +++ b/erpnext/accounts/report/payment_period_based_on_invoice_date/payment_period_based_on_invoice_date.py @@ -1,7 +1,6 @@ # Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors # License: GNU General Public License v3. See license.txt -from __future__ import unicode_literals import frappe from frappe import _ diff --git a/erpnext/accounts/report/pos_register/pos_register.py b/erpnext/accounts/report/pos_register/pos_register.py index c9463caa6db..77e7568533e 100644 --- a/erpnext/accounts/report/pos_register/pos_register.py +++ b/erpnext/accounts/report/pos_register/pos_register.py @@ -1,7 +1,6 @@ # Copyright (c) 2013, Frappe Technologies Pvt. Ltd. and contributors # For license information, please see license.txt -from __future__ import unicode_literals import frappe from frappe import _ diff --git a/erpnext/accounts/report/profit_and_loss_statement/profit_and_loss_statement.py b/erpnext/accounts/report/profit_and_loss_statement/profit_and_loss_statement.py index ef799f63bf9..882e411246b 100644 --- a/erpnext/accounts/report/profit_and_loss_statement/profit_and_loss_statement.py +++ b/erpnext/accounts/report/profit_and_loss_statement/profit_and_loss_statement.py @@ -1,7 +1,6 @@ # Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors # License: GNU General Public License v3. See license.txt -from __future__ import unicode_literals import frappe from frappe import _ diff --git a/erpnext/accounts/report/profitability_analysis/profitability_analysis.py b/erpnext/accounts/report/profitability_analysis/profitability_analysis.py index ad97808973b..3dcb86267c1 100644 --- a/erpnext/accounts/report/profitability_analysis/profitability_analysis.py +++ b/erpnext/accounts/report/profitability_analysis/profitability_analysis.py @@ -1,7 +1,6 @@ # Copyright (c) 2013, Frappe Technologies Pvt. Ltd. and contributors # For license information, please see license.txt -from __future__ import unicode_literals import frappe from frappe import _ diff --git a/erpnext/accounts/report/purchase_invoice_trends/purchase_invoice_trends.py b/erpnext/accounts/report/purchase_invoice_trends/purchase_invoice_trends.py index b26c733bc7e..406f7a50e8b 100644 --- a/erpnext/accounts/report/purchase_invoice_trends/purchase_invoice_trends.py +++ b/erpnext/accounts/report/purchase_invoice_trends/purchase_invoice_trends.py @@ -1,7 +1,6 @@ # Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors # License: GNU General Public License v3. See license.txt -from __future__ import unicode_literals from erpnext.controllers.trends import get_columns, get_data diff --git a/erpnext/accounts/report/purchase_register/purchase_register.py b/erpnext/accounts/report/purchase_register/purchase_register.py index 5d4a03ce60a..a9696bd104a 100644 --- a/erpnext/accounts/report/purchase_register/purchase_register.py +++ b/erpnext/accounts/report/purchase_register/purchase_register.py @@ -1,7 +1,6 @@ # Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors # License: GNU General Public License v3. See license.txt -from __future__ import unicode_literals import frappe from frappe import _, msgprint diff --git a/erpnext/accounts/report/received_items_to_be_billed/received_items_to_be_billed.py b/erpnext/accounts/report/received_items_to_be_billed/received_items_to_be_billed.py index adf6b29ea8f..e88675bb8d6 100644 --- a/erpnext/accounts/report/received_items_to_be_billed/received_items_to_be_billed.py +++ b/erpnext/accounts/report/received_items_to_be_billed/received_items_to_be_billed.py @@ -1,7 +1,6 @@ # Copyright (c) 2013, Frappe Technologies Pvt. Ltd. and contributors # For license information, please see license.txt -from __future__ import unicode_literals from frappe import _ diff --git a/erpnext/accounts/report/sales_invoice_trends/sales_invoice_trends.py b/erpnext/accounts/report/sales_invoice_trends/sales_invoice_trends.py index 0ec54c932b8..966b1d4fd01 100644 --- a/erpnext/accounts/report/sales_invoice_trends/sales_invoice_trends.py +++ b/erpnext/accounts/report/sales_invoice_trends/sales_invoice_trends.py @@ -1,7 +1,6 @@ # Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors # License: GNU General Public License v3. See license.txt -from __future__ import unicode_literals from erpnext.controllers.trends import get_columns, get_data diff --git a/erpnext/accounts/report/sales_payment_summary/sales_payment_summary.py b/erpnext/accounts/report/sales_payment_summary/sales_payment_summary.py index 9ad7007a2cc..3b736282cf9 100644 --- a/erpnext/accounts/report/sales_payment_summary/sales_payment_summary.py +++ b/erpnext/accounts/report/sales_payment_summary/sales_payment_summary.py @@ -1,6 +1,5 @@ # Copyright (c) 2013, Frappe Technologies Pvt. Ltd. and contributors # For license information, please see license.txt -from __future__ import unicode_literals import frappe from frappe import _ diff --git a/erpnext/accounts/report/sales_payment_summary/test_sales_payment_summary.py b/erpnext/accounts/report/sales_payment_summary/test_sales_payment_summary.py index 9fd7bc3de73..b3f6c72a3ef 100644 --- a/erpnext/accounts/report/sales_payment_summary/test_sales_payment_summary.py +++ b/erpnext/accounts/report/sales_payment_summary/test_sales_payment_summary.py @@ -1,7 +1,6 @@ # Copyright (c) 2018, Frappe Technologies Pvt. Ltd. and Contributors # License: GNU General Public License v3. See license.txt -from __future__ import unicode_literals import unittest diff --git a/erpnext/accounts/report/sales_register/sales_register.py b/erpnext/accounts/report/sales_register/sales_register.py index 57b69aa8187..a9d0081bacc 100644 --- a/erpnext/accounts/report/sales_register/sales_register.py +++ b/erpnext/accounts/report/sales_register/sales_register.py @@ -1,7 +1,6 @@ # Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors # License: GNU General Public License v3. See license.txt -from __future__ import unicode_literals import frappe from frappe import _, msgprint diff --git a/erpnext/accounts/report/share_balance/share_balance.py b/erpnext/accounts/report/share_balance/share_balance.py index 03efc9ec33a..943c4e150f0 100644 --- a/erpnext/accounts/report/share_balance/share_balance.py +++ b/erpnext/accounts/report/share_balance/share_balance.py @@ -1,7 +1,6 @@ # Copyright (c) 2013, Frappe Technologies Pvt. Ltd. and contributors # For license information, please see license.txt -from __future__ import unicode_literals import frappe from frappe import _ diff --git a/erpnext/accounts/report/share_ledger/share_ledger.py b/erpnext/accounts/report/share_ledger/share_ledger.py index 9be662220d0..b3ff6e48a6f 100644 --- a/erpnext/accounts/report/share_ledger/share_ledger.py +++ b/erpnext/accounts/report/share_ledger/share_ledger.py @@ -1,8 +1,6 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2017, Frappe Technologies Pvt. Ltd. and contributors # For license information, please see license.txt -from __future__ import unicode_literals import frappe from frappe import _ diff --git a/erpnext/accounts/report/supplier_ledger_summary/supplier_ledger_summary.py b/erpnext/accounts/report/supplier_ledger_summary/supplier_ledger_summary.py index 00316ba2652..52beeaf660c 100644 --- a/erpnext/accounts/report/supplier_ledger_summary/supplier_ledger_summary.py +++ b/erpnext/accounts/report/supplier_ledger_summary/supplier_ledger_summary.py @@ -1,7 +1,6 @@ # Copyright (c) 2013, Frappe Technologies Pvt. Ltd. and contributors # For license information, please see license.txt -from __future__ import unicode_literals from erpnext.accounts.report.customer_ledger_summary.customer_ledger_summary import ( PartyLedgerSummaryReport, diff --git a/erpnext/accounts/report/tax_detail/tax_detail.py b/erpnext/accounts/report/tax_detail/tax_detail.py index f03498d5b20..eeb8483586f 100644 --- a/erpnext/accounts/report/tax_detail/tax_detail.py +++ b/erpnext/accounts/report/tax_detail/tax_detail.py @@ -2,7 +2,6 @@ # For license information, please see license.txt # Contributed by Case Solved and sponsored by Nulight Studios -from __future__ import unicode_literals import json diff --git a/erpnext/accounts/report/tax_detail/test_tax_detail.py b/erpnext/accounts/report/tax_detail/test_tax_detail.py index e74b905db17..bf668ab779d 100644 --- a/erpnext/accounts/report/tax_detail/test_tax_detail.py +++ b/erpnext/accounts/report/tax_detail/test_tax_detail.py @@ -1,5 +1,3 @@ -from __future__ import unicode_literals - import datetime import json import os diff --git a/erpnext/accounts/report/tds_computation_summary/tds_computation_summary.json b/erpnext/accounts/report/tds_computation_summary/tds_computation_summary.json index dfc4b18e07d..91f079824d2 100644 --- a/erpnext/accounts/report/tds_computation_summary/tds_computation_summary.json +++ b/erpnext/accounts/report/tds_computation_summary/tds_computation_summary.json @@ -1,12 +1,15 @@ { - "add_total_row": 0, + "add_total_row": 1, + "columns": [], "creation": "2018-08-21 11:25:00.551823", + "disable_prepared_report": 0, "disabled": 0, "docstatus": 0, "doctype": "Report", + "filters": [], "idx": 0, "is_standard": "Yes", - "modified": "2018-09-21 11:25:00.551823", + "modified": "2021-09-20 17:43:39.518851", "modified_by": "Administrator", "module": "Accounts", "name": "TDS Computation Summary", diff --git a/erpnext/accounts/report/tds_computation_summary/tds_computation_summary.py b/erpnext/accounts/report/tds_computation_summary/tds_computation_summary.py index c4a8c7a899a..07f2e435e41 100644 --- a/erpnext/accounts/report/tds_computation_summary/tds_computation_summary.py +++ b/erpnext/accounts/report/tds_computation_summary/tds_computation_summary.py @@ -1,12 +1,9 @@ -from __future__ import unicode_literals - import frappe from frappe import _ -from frappe.utils import flt -from erpnext.accounts.doctype.tax_withholding_category.tax_withholding_category import ( - get_advance_vouchers, - get_debit_note_amount, +from erpnext.accounts.report.tds_payable_monthly.tds_payable_monthly import ( + get_result, + get_tds_docs, ) from erpnext.accounts.utils import get_fiscal_year @@ -17,9 +14,12 @@ def execute(filters=None): filters.naming_series = frappe.db.get_single_value('Buying Settings', 'supp_master_name') columns = get_columns(filters) - res = get_result(filters) + tds_docs, tds_accounts, tax_category_map = get_tds_docs(filters) - return columns, res + res = get_result(filters, tds_docs, tds_accounts, tax_category_map) + final_result = group_by_supplier_and_category(res) + + return columns, final_result def validate_filters(filters): ''' Validate if dates are properly set and lie in the same fiscal year''' @@ -33,81 +33,39 @@ def validate_filters(filters): filters["fiscal_year"] = from_year -def get_result(filters): - # if no supplier selected, fetch data for all tds applicable supplier - # else fetch relevant data for selected supplier - pan = "pan" if frappe.db.has_column("Supplier", "pan") else "tax_id" - fields = ["name", pan+" as pan", "tax_withholding_category", "supplier_type", "supplier_name"] +def group_by_supplier_and_category(data): + supplier_category_wise_map = {} - if filters.supplier: - filters.supplier = frappe.db.get_list('Supplier', - {"name": filters.supplier}, fields) - else: - filters.supplier = frappe.db.get_list('Supplier', - {"tax_withholding_category": ["!=", ""]}, fields) + for row in data: + supplier_category_wise_map.setdefault((row.get('supplier'), row.get('section_code')), { + 'pan': row.get('pan'), + 'supplier': row.get('supplier'), + 'supplier_name': row.get('supplier_name'), + 'section_code': row.get('section_code'), + 'entity_type': row.get('entity_type'), + 'tds_rate': row.get('tds_rate'), + 'total_amount_credited': 0.0, + 'tds_deducted': 0.0 + }) + supplier_category_wise_map.get((row.get('supplier'), row.get('section_code')))['total_amount_credited'] += \ + row.get('total_amount_credited', 0.0) + + supplier_category_wise_map.get((row.get('supplier'), row.get('section_code')))['tds_deducted'] += \ + row.get('tds_deducted', 0.0) + + final_result = get_final_result(supplier_category_wise_map) + + return final_result + + +def get_final_result(supplier_category_wise_map): out = [] - for supplier in filters.supplier: - tds = frappe.get_doc("Tax Withholding Category", supplier.tax_withholding_category) - rate = [d.tax_withholding_rate for d in tds.rates if d.fiscal_year == filters.fiscal_year] - - if rate: - rate = rate[0] - - try: - account = [d.account for d in tds.accounts if d.company == filters.company][0] - - except IndexError: - account = [] - total_invoiced_amount, tds_deducted = get_invoice_and_tds_amount(supplier.name, account, - filters.company, filters.from_date, filters.to_date, filters.fiscal_year) - - if total_invoiced_amount or tds_deducted: - row = [supplier.pan, supplier.name] - - if filters.naming_series == 'Naming Series': - row.append(supplier.supplier_name) - - row.extend([tds.name, supplier.supplier_type, rate, total_invoiced_amount, tds_deducted]) - out.append(row) + for key, value in supplier_category_wise_map.items(): + out.append(value) return out -def get_invoice_and_tds_amount(supplier, account, company, from_date, to_date, fiscal_year): - ''' calculate total invoice amount and total tds deducted for given supplier ''' - - entries = frappe.db.sql(""" - select voucher_no, credit - from `tabGL Entry` - where party in (%s) and credit > 0 - and company=%s and is_cancelled = 0 - and posting_date between %s and %s - """, (supplier, company, from_date, to_date), as_dict=1) - - supplier_credit_amount = flt(sum(d.credit for d in entries)) - - vouchers = [d.voucher_no for d in entries] - vouchers += get_advance_vouchers([supplier], company=company, - from_date=from_date, to_date=to_date) - - tds_deducted = 0 - if vouchers: - tds_deducted = flt(frappe.db.sql(""" - select sum(credit) - from `tabGL Entry` - where account=%s and posting_date between %s and %s - and company=%s and credit > 0 and voucher_no in ({0}) - """.format(', '.join("'%s'" % d for d in vouchers)), - (account, from_date, to_date, company))[0][0]) - - date_range_filter = [fiscal_year, from_date, to_date] - - debit_note_amount = get_debit_note_amount([supplier], date_range_filter, company=company) - - total_invoiced_amount = supplier_credit_amount + tds_deducted - debit_note_amount - - return total_invoiced_amount, tds_deducted - def get_columns(filters): columns = [ { @@ -149,7 +107,7 @@ def get_columns(filters): { "label": _("TDS Rate %"), "fieldname": "tds_rate", - "fieldtype": "Float", + "fieldtype": "Percent", "width": 90 }, { diff --git a/erpnext/accounts/report/tds_payable_monthly/tds_payable_monthly.js b/erpnext/accounts/report/tds_payable_monthly/tds_payable_monthly.js index 72de318a48c..ff2aa306017 100644 --- a/erpnext/accounts/report/tds_payable_monthly/tds_payable_monthly.js +++ b/erpnext/accounts/report/tds_payable_monthly/tds_payable_monthly.js @@ -16,69 +16,6 @@ frappe.query_reports["TDS Payable Monthly"] = { "label": __("Supplier"), "fieldtype": "Link", "options": "Supplier", - "get_query": function() { - return { - "filters": { - "tax_withholding_category": ["!=", ""], - } - } - }, - on_change: function() { - frappe.query_report.set_filter_value("purchase_invoice", ""); - frappe.query_report.refresh(); - } - }, - { - "fieldname":"purchase_invoice", - "label": __("Purchase Invoice"), - "fieldtype": "Link", - "options": "Purchase Invoice", - "get_query": function() { - return { - "filters": { - "name": ["in", frappe.query_report.invoices] - } - } - }, - on_change: function() { - let supplier = frappe.query_report.get_filter_value('supplier'); - if(!supplier) return; // return if no supplier selected - - // filter invoices based on selected supplier - let invoices = []; - frappe.query_report.invoice_data.map(d => { - if(d.supplier==supplier) - invoices.push(d.name) - }); - frappe.query_report.invoices = invoices; - frappe.query_report.refresh(); - } - }, - { - "fieldname":"purchase_order", - "label": __("Purchase Order"), - "fieldtype": "Link", - "options": "Purchase Order", - "get_query": function() { - return { - "filters": { - "name": ["in", frappe.query_report.invoices] - } - } - }, - on_change: function() { - let supplier = frappe.query_report.get_filter_value('supplier'); - if(!supplier) return; // return if no supplier selected - - // filter invoices based on selected supplier - let invoices = []; - frappe.query_report.invoice_data.map(d => { - if(d.supplier==supplier) - invoices.push(d.name) - }); - frappe.query_report.invoices = invoices; - frappe.query_report.refresh(); - } }, { "fieldname":"from_date", @@ -96,23 +33,5 @@ frappe.query_reports["TDS Payable Monthly"] = { "reqd": 1, "width": "60px" } - ], - - onload: function(report) { - // fetch all tds applied invoices - frappe.call({ - "method": "erpnext.accounts.report.tds_payable_monthly.tds_payable_monthly.get_tds_invoices_and_orders", - callback: function(r) { - let invoices = []; - - r.message.map(d => { - invoices.push(d.name); - }); - - report["invoice_data"] = r.message.invoices; - report["invoices"] = invoices; - - } - }); - } + ] } diff --git a/erpnext/accounts/report/tds_payable_monthly/tds_payable_monthly.json b/erpnext/accounts/report/tds_payable_monthly/tds_payable_monthly.json index 557a62d8fea..4d555bd8ba1 100644 --- a/erpnext/accounts/report/tds_payable_monthly/tds_payable_monthly.json +++ b/erpnext/accounts/report/tds_payable_monthly/tds_payable_monthly.json @@ -1,13 +1,15 @@ { "add_total_row": 1, + "columns": [], "creation": "2018-08-21 11:32:30.874923", "disable_prepared_report": 0, "disabled": 0, "docstatus": 0, "doctype": "Report", + "filters": [], "idx": 0, "is_standard": "Yes", - "modified": "2019-09-24 13:46:16.473711", + "modified": "2021-09-20 12:05:50.387572", "modified_by": "Administrator", "module": "Accounts", "name": "TDS Payable Monthly", diff --git a/erpnext/accounts/report/tds_payable_monthly/tds_payable_monthly.py b/erpnext/accounts/report/tds_payable_monthly/tds_payable_monthly.py index 9e1382b9222..a3a45d1e79c 100644 --- a/erpnext/accounts/report/tds_payable_monthly/tds_payable_monthly.py +++ b/erpnext/accounts/report/tds_payable_monthly/tds_payable_monthly.py @@ -1,26 +1,18 @@ # Copyright (c) 2013, Frappe Technologies Pvt. Ltd. and contributors # For license information, please see license.txt -from __future__ import unicode_literals import frappe from frappe import _ def execute(filters=None): - filters["invoices"] = frappe.cache().hget("invoices", frappe.session.user) validate_filters(filters) - set_filters(filters) - - # TDS payment entries - payment_entries = get_payment_entires(filters) + tds_docs, tds_accounts, tax_category_map = get_tds_docs(filters) columns = get_columns(filters) - if not filters.get("invoices"): - return columns, [] - - res = get_result(filters, payment_entries) + res = get_result(filters, tds_docs, tds_accounts, tax_category_map) return columns, res def validate_filters(filters): @@ -28,109 +20,59 @@ def validate_filters(filters): if filters.from_date > filters.to_date: frappe.throw(_("From Date must be before To Date")) -def set_filters(filters): - invoices = [] - - if not filters.get("invoices"): - filters["invoices"] = get_tds_invoices_and_orders() - - if filters.supplier and filters.purchase_invoice: - for d in filters["invoices"]: - if d.name == filters.purchase_invoice and d.supplier == filters.supplier: - invoices.append(d) - elif filters.supplier and not filters.purchase_invoice: - for d in filters["invoices"]: - if d.supplier == filters.supplier: - invoices.append(d) - elif filters.purchase_invoice and not filters.supplier: - for d in filters["invoices"]: - if d.name == filters.purchase_invoice: - invoices.append(d) - elif filters.supplier and filters.purchase_order: - for d in filters.get("invoices"): - if d.name == filters.purchase_order and d.supplier == filters.supplier: - invoices.append(d) - elif filters.supplier and not filters.purchase_order: - for d in filters.get("invoices"): - if d.supplier == filters.supplier: - invoices.append(d) - elif filters.purchase_order and not filters.supplier: - for d in filters.get("invoices"): - if d.name == filters.purchase_order: - invoices.append(d) - - filters["invoices"] = invoices if invoices else filters["invoices"] - filters.naming_series = frappe.db.get_single_value('Buying Settings', 'supp_master_name') - - #print(filters.get('invoices')) - -def get_result(filters, payment_entries): - supplier_map, tds_docs = get_supplier_map(filters, payment_entries) - documents = [d.get('name') for d in filters.get('invoices')] + [d.get('name') for d in payment_entries] - - gle_map = get_gle_map(filters, documents) +def get_result(filters, tds_docs, tds_accounts, tax_category_map): + supplier_map = get_supplier_pan_map() + tax_rate_map = get_tax_rate_map(filters) + gle_map = get_gle_map(filters, tds_docs) out = [] - for d in gle_map: + for name, details in gle_map.items(): tds_deducted, total_amount_credited = 0, 0 - supplier = supplier_map[d] + tax_withholding_category = tax_category_map.get(name) + rate = tax_rate_map.get(tax_withholding_category) - tds_doc = tds_docs[supplier.tax_withholding_category] - account_list = [i.account for i in tds_doc.accounts if i.company == filters.company] + for entry in details: + supplier = entry.party or entry.against + posting_date = entry.posting_date + voucher_type = entry.voucher_type - if account_list: - account = account_list[0] + if entry.account in tds_accounts: + tds_deducted += (entry.credit - entry.debit) - for k in gle_map[d]: - if k.party == supplier_map[d] and k.credit > 0: - total_amount_credited += (k.credit - k.debit) - elif account_list and k.account == account and (k.credit - k.debit) > 0: - tds_deducted = (k.credit - k.debit) - total_amount_credited += (k.credit - k.debit) - voucher_type = k.voucher_type + total_amount_credited += (entry.credit - entry.debit) - rate = [i.tax_withholding_rate for i in tds_doc.rates - if i.fiscal_year == gle_map[d][0].fiscal_year] - - if rate and len(rate) > 0 and tds_deducted: - rate = rate[0] - - row = [supplier.pan, supplier.name] + if rate and tds_deducted: + row = { + 'pan' if frappe.db.has_column('Supplier', 'pan') else 'tax_id': supplier_map.get(supplier, {}).get('pan'), + 'supplier': supplier_map.get(supplier, {}).get('name') + } if filters.naming_series == 'Naming Series': - row.append(supplier.supplier_name) + row.update({'supplier_name': supplier_map.get(supplier, {}).get('supplier_name')}) + + row.update({ + 'section_code': tax_withholding_category, + 'entity_type': supplier_map.get(supplier, {}).get('supplier_type'), + 'tds_rate': rate, + 'total_amount_credited': total_amount_credited, + 'tds_deducted': tds_deducted, + 'transaction_date': posting_date, + 'transaction_type': voucher_type, + 'ref_no': name + }) - row.extend([tds_doc.name, supplier.supplier_type, rate, total_amount_credited, - tds_deducted, gle_map[d][0].posting_date, voucher_type, d]) out.append(row) return out -def get_supplier_map(filters, payment_entries): - # create a supplier_map of the form {"purchase_invoice": {supplier_name, pan, tds_name}} - # pre-fetch all distinct applicable tds docs - supplier_map, tds_docs = {}, {} - pan = "pan" if frappe.db.has_column("Supplier", "pan") else "tax_id" - supplier_list = [d.supplier for d in filters["invoices"]] +def get_supplier_pan_map(): + supplier_map = frappe._dict() + suppliers = frappe.db.get_all('Supplier', fields=['name', 'pan', 'supplier_type', 'supplier_name']) - supplier_detail = frappe.db.get_all('Supplier', - {"name": ["in", supplier_list]}, - ["tax_withholding_category", "name", pan+" as pan", "supplier_type", "supplier_name"]) + for d in suppliers: + supplier_map[d.name] = d - for d in filters["invoices"]: - supplier_map[d.get("name")] = [k for k in supplier_detail - if k.name == d.get("supplier")][0] - - for d in payment_entries: - supplier_map[d.get("name")] = [k for k in supplier_detail - if k.name == d.get("supplier")][0] - - for d in supplier_detail: - if d.get("tax_withholding_category") not in tds_docs: - tds_docs[d.get("tax_withholding_category")] = \ - frappe.get_doc("Tax Withholding Category", d.get("tax_withholding_category")) - - return supplier_map, tds_docs + return supplier_map def get_gle_map(filters, documents): # create gle_map of the form @@ -140,10 +82,9 @@ def get_gle_map(filters, documents): gle = frappe.db.get_all('GL Entry', { "voucher_no": ["in", documents], - 'is_cancelled': 0, - 'posting_date': ("between", [filters.get('from_date'), filters.get('to_date')]), + "credit": (">", 0) }, - ["fiscal_year", "credit", "debit", "account", "voucher_no", "posting_date", "voucher_type"], + ["credit", "debit", "account", "voucher_no", "posting_date", "voucher_type", "against", "party"], ) for d in gle: @@ -233,39 +174,57 @@ def get_columns(filters): return columns -def get_payment_entires(filters): - filter_dict = { - 'posting_date': ("between", [filters.get('from_date'), filters.get('to_date')]), - 'party_type': 'Supplier', - 'apply_tax_withholding_amount': 1 +def get_tds_docs(filters): + tds_documents = [] + purchase_invoices = [] + payment_entries = [] + journal_entries = [] + tax_category_map = {} + + tds_accounts = frappe.get_all("Tax Withholding Account", {'company': filters.get('company')}, + pluck="account") + + query_filters = { + "credit": ('>', 0), + "account": ("in", tds_accounts), + "posting_date": ("between", [filters.get("from_date"), filters.get("to_date")]), + "is_cancelled": 0 } - if filters.get('purchase_invoice') or filters.get('purchase_order'): - parent = frappe.db.get_all('Payment Entry Reference', - {'reference_name': ('in', [d.get('name') for d in filters.get('invoices')])}, ['parent']) + if filters.get('supplier'): + query_filters.update({'against': filters.get('supplier')}) - filter_dict.update({'name': ('in', [d.get('parent') for d in parent])}) + tds_docs = frappe.get_all("GL Entry", query_filters, ["voucher_no", "voucher_type", "against", "party"]) - payment_entries = frappe.get_all('Payment Entry', fields=['name', 'party_name as supplier'], - filters=filter_dict) + for d in tds_docs: + if d.voucher_type == "Purchase Invoice": + purchase_invoices.append(d.voucher_no) + elif d.voucher_type == "Payment Entry": + payment_entries.append(d.voucher_no) + elif d.voucher_type == "Journal Entry": + journal_entries.append(d.voucher_no) - return payment_entries + tds_documents.append(d.voucher_no) -@frappe.whitelist() -def get_tds_invoices_and_orders(): - # fetch tds applicable supplier and fetch invoices for these suppliers - suppliers = [d.name for d in frappe.db.get_list("Supplier", - {"tax_withholding_category": ["!=", ""]}, ["name"])] + if purchase_invoices: + get_tax_category_map(purchase_invoices, 'Purchase Invoice', tax_category_map) - invoices = frappe.db.get_list("Purchase Invoice", - {"supplier": ["in", suppliers]}, ["name", "supplier"]) + if payment_entries: + get_tax_category_map(payment_entries, 'Payment Entry', tax_category_map) - orders = frappe.db.get_list("Purchase Order", - {"supplier": ["in", suppliers]}, ["name", "supplier"]) + if journal_entries: + get_tax_category_map(journal_entries, 'Journal Entry', tax_category_map) - invoices = invoices + orders - invoices = [d for d in invoices if d.supplier] + return tds_documents, tds_accounts, tax_category_map - frappe.cache().hset("invoices", frappe.session.user, invoices) +def get_tax_category_map(vouchers, doctype, tax_category_map): + tax_category_map.update(frappe._dict(frappe.get_all(doctype, + filters = {'name': ('in', vouchers)}, fields=['name', 'tax_withholding_category'], as_list=1))) - return invoices +def get_tax_rate_map(filters): + rate_map = frappe.get_all('Tax Withholding Rate', filters={ + 'from_date': ('<=', filters.get('from_date')), + 'to_date': ('>=', filters.get('to_date')) + }, fields=['parent', 'tax_withholding_rate'], as_list=1) + + return frappe._dict(rate_map) \ No newline at end of file diff --git a/erpnext/accounts/report/trial_balance/trial_balance.py b/erpnext/accounts/report/trial_balance/trial_balance.py index d65bcc4ada3..bda44f66aa1 100644 --- a/erpnext/accounts/report/trial_balance/trial_balance.py +++ b/erpnext/accounts/report/trial_balance/trial_balance.py @@ -1,7 +1,6 @@ # Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors # License: GNU General Public License v3. See license.txt -from __future__ import unicode_literals import frappe from frappe import _ diff --git a/erpnext/accounts/report/trial_balance_for_party/trial_balance_for_party.py b/erpnext/accounts/report/trial_balance_for_party/trial_balance_for_party.py index 8e245443c33..d843dfd3ce3 100644 --- a/erpnext/accounts/report/trial_balance_for_party/trial_balance_for_party.py +++ b/erpnext/accounts/report/trial_balance_for_party/trial_balance_for_party.py @@ -1,7 +1,6 @@ # Copyright (c) 2013, Frappe Technologies Pvt. Ltd. and contributors # For license information, please see license.txt -from __future__ import unicode_literals import frappe from frappe import _ diff --git a/erpnext/accounts/report/unpaid_expense_claim/unpaid_expense_claim.js b/erpnext/accounts/report/unpaid_expense_claim/unpaid_expense_claim.js index 811414aaf07..f0ba78c9608 100644 --- a/erpnext/accounts/report/unpaid_expense_claim/unpaid_expense_claim.js +++ b/erpnext/accounts/report/unpaid_expense_claim/unpaid_expense_claim.js @@ -4,9 +4,10 @@ frappe.query_reports["Unpaid Expense Claim"] = { "filters": [ { - "fieldname":"employee", + "fieldname": "employee", "label": __("Employee"), - "fieldtype": "Link" + "fieldtype": "Link", + "options": "Employee" } ] } diff --git a/erpnext/accounts/report/unpaid_expense_claim/unpaid_expense_claim.py b/erpnext/accounts/report/unpaid_expense_claim/unpaid_expense_claim.py index 71fe4a294a3..26b938966b3 100644 --- a/erpnext/accounts/report/unpaid_expense_claim/unpaid_expense_claim.py +++ b/erpnext/accounts/report/unpaid_expense_claim/unpaid_expense_claim.py @@ -1,7 +1,6 @@ # Copyright (c) 2013, Frappe Technologies Pvt. Ltd. and contributors # For license information, please see license.txt -from __future__ import unicode_literals import frappe from frappe import _ diff --git a/erpnext/accounts/report/utils.py b/erpnext/accounts/report/utils.py index 57ff9b0ec9e..c38e4b8c7f3 100644 --- a/erpnext/accounts/report/utils.py +++ b/erpnext/accounts/report/utils.py @@ -1,5 +1,3 @@ -from __future__ import unicode_literals - import frappe from frappe.utils import flt, formatdate, get_datetime_str @@ -100,15 +98,15 @@ def convert_to_presentation_currency(gl_entries, currency_info, company): if entry.get('credit'): entry['credit'] = credit_in_account_currency else: - value = debit or credit date = currency_info['report_date'] - converted_value = convert(value, presentation_currency, company_currency, date) + converted_debit_value = convert(debit, presentation_currency, company_currency, date) + converted_credit_value = convert(credit, presentation_currency, company_currency, date) if entry.get('debit'): - entry['debit'] = converted_value + entry['debit'] = converted_debit_value if entry.get('credit'): - entry['credit'] = converted_value + entry['credit'] = converted_credit_value converted_gl_list.append(entry) diff --git a/erpnext/accounts/test/test_utils.py b/erpnext/accounts/test/test_utils.py index d7b60daa37b..effc913da05 100644 --- a/erpnext/accounts/test/test_utils.py +++ b/erpnext/accounts/test/test_utils.py @@ -1,25 +1,50 @@ -from __future__ import unicode_literals - import unittest from frappe.test_runner import make_test_objects from erpnext.accounts.party import get_party_shipping_address +from erpnext.accounts.utils import get_future_stock_vouchers, get_voucherwise_gl_entries +from erpnext.stock.doctype.purchase_receipt.test_purchase_receipt import make_purchase_receipt class TestUtils(unittest.TestCase): @classmethod def setUpClass(cls): super(TestUtils, cls).setUpClass() - make_test_objects('Address', ADDRESS_RECORDS) + make_test_objects("Address", ADDRESS_RECORDS) def test_get_party_shipping_address(self): - address = get_party_shipping_address('Customer', '_Test Customer 1') - self.assertEqual(address, '_Test Billing Address 2 Title-Billing') + address = get_party_shipping_address("Customer", "_Test Customer 1") + self.assertEqual(address, "_Test Billing Address 2 Title-Billing") def test_get_party_shipping_address2(self): - address = get_party_shipping_address('Customer', '_Test Customer 2') - self.assertEqual(address, '_Test Shipping Address 2 Title-Shipping') + address = get_party_shipping_address("Customer", "_Test Customer 2") + self.assertEqual(address, "_Test Shipping Address 2 Title-Shipping") + + def test_get_voucher_wise_gl_entry(self): + + pr = make_purchase_receipt( + item_code="_Test Item", + posting_date="2021-02-01", + rate=100, + qty=1, + warehouse="Stores - TCP1", + company="_Test Company with perpetual inventory", + ) + + future_vouchers = get_future_stock_vouchers("2021-01-01", "00:00:00", for_items=["_Test Item"]) + + voucher_type_and_no = ("Purchase Receipt", pr.name) + self.assertTrue( + voucher_type_and_no in future_vouchers, + msg="get_future_stock_vouchers not returning correct value", + ) + + posting_date = "2021-01-01" + gl_entries = get_voucherwise_gl_entries(future_vouchers, posting_date) + self.assertTrue( + voucher_type_and_no in gl_entries, msg="get_voucherwise_gl_entries not returning expected GLes", + ) ADDRESS_RECORDS = [ @@ -31,12 +56,8 @@ ADDRESS_RECORDS = [ "city": "Lagos", "country": "Nigeria", "links": [ - { - "link_doctype": "Customer", - "link_name": "_Test Customer 2", - "doctype": "Dynamic Link" - } - ] + {"link_doctype": "Customer", "link_name": "_Test Customer 2", "doctype": "Dynamic Link"} + ], }, { "doctype": "Address", @@ -46,12 +67,8 @@ ADDRESS_RECORDS = [ "city": "Lagos", "country": "Nigeria", "links": [ - { - "link_doctype": "Customer", - "link_name": "_Test Customer 2", - "doctype": "Dynamic Link" - } - ] + {"link_doctype": "Customer", "link_name": "_Test Customer 2", "doctype": "Dynamic Link"} + ], }, { "doctype": "Address", @@ -62,12 +79,8 @@ ADDRESS_RECORDS = [ "country": "Nigeria", "is_shipping_address": "1", "links": [ - { - "link_doctype": "Customer", - "link_name": "_Test Customer 2", - "doctype": "Dynamic Link" - } - ] + {"link_doctype": "Customer", "link_name": "_Test Customer 2", "doctype": "Dynamic Link"} + ], }, { "doctype": "Address", @@ -78,11 +91,7 @@ ADDRESS_RECORDS = [ "country": "Nigeria", "is_shipping_address": "1", "links": [ - { - "link_doctype": "Customer", - "link_name": "_Test Customer 1", - "doctype": "Dynamic Link" - } - ] - } + {"link_doctype": "Customer", "link_name": "_Test Customer 1", "doctype": "Dynamic Link"} + ], + }, ] diff --git a/erpnext/accounts/utils.py b/erpnext/accounts/utils.py index 4692869343f..39e84e3ceff 100644 --- a/erpnext/accounts/utils.py +++ b/erpnext/accounts/utils.py @@ -1,8 +1,8 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors # License: GNU General Public License v3. See license.txt -from __future__ import unicode_literals + +from json import loads import frappe import frappe.defaults @@ -447,7 +447,8 @@ def update_reference_in_journal_entry(d, journal_entry, do_not_save=False): # new row with references new_row = journal_entry.append("accounts") - new_row.update(jv_detail.as_dict().copy()) + + new_row.update((frappe.copy_doc(jv_detail)).as_dict()) new_row.set(d["dr_or_cr"], d["allocated_amount"]) new_row.set('debit' if d['dr_or_cr'] == 'debit_in_account_currency' else 'credit', @@ -787,16 +788,28 @@ def get_children(doctype, parent, company, is_root=False): if doctype == 'Account': sort_accounts(acc, is_root, key="value") - company_currency = frappe.get_cached_value('Company', company, "default_currency") - for each in acc: - each["company_currency"] = company_currency - each["balance"] = flt(get_balance_on(each.get("value"), in_account_currency=False, company=company)) - - if each.account_currency != company_currency: - each["balance_in_account_currency"] = flt(get_balance_on(each.get("value"), company=company)) return acc +@frappe.whitelist() +def get_account_balances(accounts, company): + + if isinstance(accounts, str): + accounts = loads(accounts) + + if not accounts: + return [] + + company_currency = frappe.get_cached_value("Company", company, "default_currency") + + for account in accounts: + account["company_currency"] = company_currency + account["balance"] = flt(get_balance_on(account["value"], in_account_currency=False, company=company)) + if account["account_currency"] and account["account_currency"] != company_currency: + account["balance_in_account_currency"] = flt(get_balance_on(account["value"], company=company)) + + return accounts + def create_payment_gateway_account(gateway, payment_channel="Email"): from erpnext.setup.setup_wizard.operations.install_fixtures import create_bank_account @@ -963,6 +976,9 @@ def get_voucherwise_gl_entries(future_stock_vouchers, posting_date): Only fetches GLE fields required for comparing with new GLE. Check compare_existing_and_expected_gle function below. + + returns: + Dict[Tuple[voucher_type, voucher_no], List[GL Entries]] """ gl_entries = {} if not future_stock_vouchers: @@ -971,7 +987,7 @@ def get_voucherwise_gl_entries(future_stock_vouchers, posting_date): voucher_nos = [d[1] for d in future_stock_vouchers] gles = frappe.db.sql(""" - select name, account, credit, debit, cost_center, project + select name, account, credit, debit, cost_center, project, voucher_type, voucher_no from `tabGL Entry` where posting_date >= %s and voucher_no in (%s)""" % diff --git a/erpnext/accounts/workspace/accounting/accounting.json b/erpnext/accounts/workspace/accounting/accounting.json index 2b26ac50900..33d17488256 100644 --- a/erpnext/accounts/workspace/accounting/accounting.json +++ b/erpnext/accounts/workspace/accounting/accounting.json @@ -1,5 +1,4 @@ { - "category": "", "charts": [ { "chart_name": "Profit and Loss", @@ -8,18 +7,12 @@ ], "content": "[{\"type\": \"onboarding\", \"data\": {\"onboarding_name\":\"Accounts\", \"col\": 12}}, {\"type\": \"chart\", \"data\": {\"chart_name\": \"Profit and Loss\", \"col\": 12}}, {\"type\": \"spacer\", \"data\": {\"col\": 12}}, {\"type\": \"header\", \"data\": {\"text\": \"Your Shortcuts\", \"level\": 4, \"col\": 12}}, {\"type\": \"shortcut\", \"data\": {\"shortcut_name\": \"Chart of Accounts\", \"col\": 4}}, {\"type\": \"shortcut\", \"data\": {\"shortcut_name\": \"Sales Invoice\", \"col\": 4}}, {\"type\": \"shortcut\", \"data\": {\"shortcut_name\": \"Purchase Invoice\", \"col\": 4}}, {\"type\": \"shortcut\", \"data\": {\"shortcut_name\": \"Journal Entry\", \"col\": 4}}, {\"type\": \"shortcut\", \"data\": {\"shortcut_name\": \"Payment Entry\", \"col\": 4}}, {\"type\": \"shortcut\", \"data\": {\"shortcut_name\": \"Accounts Receivable\", \"col\": 4}}, {\"type\": \"shortcut\", \"data\": {\"shortcut_name\": \"General Ledger\", \"col\": 4}}, {\"type\": \"shortcut\", \"data\": {\"shortcut_name\": \"Trial Balance\", \"col\": 4}}, {\"type\": \"shortcut\", \"data\": {\"shortcut_name\": \"Dashboard\", \"col\": 4}}, {\"type\": \"spacer\", \"data\": {\"col\": 12}}, {\"type\": \"header\", \"data\": {\"text\": \"Reports & Masters\", \"level\": 4, \"col\": 12}}, {\"type\": \"card\", \"data\": {\"card_name\": \"Accounting Masters\", \"col\": 4}}, {\"type\": \"card\", \"data\": {\"card_name\": \"General Ledger\", \"col\": 4}}, {\"type\": \"card\", \"data\": {\"card_name\": \"Accounts Receivable\", \"col\": 4}}, {\"type\": \"card\", \"data\": {\"card_name\": \"Accounts Payable\", \"col\": 4}}, {\"type\": \"card\", \"data\": {\"card_name\": \"Reports\", \"col\": 4}}, {\"type\": \"card\", \"data\": {\"card_name\": \"Financial Statements\", \"col\": 4}}, {\"type\": \"card\", \"data\": {\"card_name\": \"Multi Currency\", \"col\": 4}}, {\"type\": \"card\", \"data\": {\"card_name\": \"Settings\", \"col\": 4}}, {\"type\": \"card\", \"data\": {\"card_name\": \"Bank Statement\", \"col\": 4}}, {\"type\": \"card\", \"data\": {\"card_name\": \"Subscription Management\", \"col\": 4}}, {\"type\": \"card\", \"data\": {\"card_name\": \"Goods and Services Tax (GST India)\", \"col\": 4}}, {\"type\": \"card\", \"data\": {\"card_name\": \"Share Management\", \"col\": 4}}, {\"type\": \"card\", \"data\": {\"card_name\": \"Cost Center and Budgeting\", \"col\": 4}}, {\"type\": \"card\", \"data\": {\"card_name\": \"Opening and Closing\", \"col\": 4}}, {\"type\": \"card\", \"data\": {\"card_name\": \"Taxes\", \"col\": 4}}, {\"type\": \"card\", \"data\": {\"card_name\": \"Profitability\", \"col\": 4}}]", "creation": "2020-03-02 15:41:59.515192", - "developer_mode_only": 0, - "disable_user_customization": 0, "docstatus": 0, "doctype": "Workspace", - "extends": "", - "extends_another_page": 0, "for_user": "", "hide_custom": 0, "icon": "accounting", "idx": 0, - "is_default": 0, - "is_standard": 0, "label": "Accounting", "links": [ { @@ -533,6 +526,17 @@ "only_for": "United Arab Emirates", "type": "Link" }, + { + "dependencies": "GL Entry", + "hidden": 0, + "is_query_report": 1, + "label": "KSA VAT Report", + "link_to": "KSA VAT", + "link_type": "Report", + "onboard": 0, + "only_for": "Saudi Arabia", + "type": "Link" + }, { "hidden": 0, "is_query_report": 0, @@ -1153,6 +1157,16 @@ "onboard": 0, "type": "Link" }, + { + "hidden": 0, + "is_query_report": 0, + "label": "KSA VAT Setting", + "link_to": "KSA VAT Setting", + "link_type": "DocType", + "onboard": 0, + "only_for": "Saudi Arabia", + "type": "Link" + }, { "hidden": 0, "is_query_report": 0, @@ -1206,15 +1220,12 @@ "type": "Link" } ], - "modified": "2021-08-27 12:15:52.872470", + "modified": "2021-08-27 12:15:52.872471", "modified_by": "Administrator", "module": "Accounts", "name": "Accounting", - "onboarding": "Accounts", "owner": "Administrator", "parent_page": "", - "pin_to_bottom": 0, - "pin_to_top": 0, "public": 1, "restrict_to_domain": "", "roles": [], diff --git a/erpnext/agriculture/doctype/agriculture_analysis_criteria/agriculture_analysis_criteria.py b/erpnext/agriculture/doctype/agriculture_analysis_criteria/agriculture_analysis_criteria.py index b0441c236fc..19459927a5a 100644 --- a/erpnext/agriculture/doctype/agriculture_analysis_criteria/agriculture_analysis_criteria.py +++ b/erpnext/agriculture/doctype/agriculture_analysis_criteria/agriculture_analysis_criteria.py @@ -1,8 +1,6 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2017, Frappe Technologies Pvt. Ltd. and contributors # For license information, please see license.txt -from __future__ import unicode_literals from frappe.model.document import Document diff --git a/erpnext/agriculture/doctype/agriculture_analysis_criteria/test_agriculture_analysis_criteria.py b/erpnext/agriculture/doctype/agriculture_analysis_criteria/test_agriculture_analysis_criteria.py index 4213e45c078..91e6f3fa0c9 100644 --- a/erpnext/agriculture/doctype/agriculture_analysis_criteria/test_agriculture_analysis_criteria.py +++ b/erpnext/agriculture/doctype/agriculture_analysis_criteria/test_agriculture_analysis_criteria.py @@ -1,7 +1,5 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2017, Frappe Technologies Pvt. Ltd. and Contributors # See license.txt -from __future__ import unicode_literals import unittest diff --git a/erpnext/agriculture/doctype/agriculture_task/agriculture_task.py b/erpnext/agriculture/doctype/agriculture_task/agriculture_task.py index 642f49189da..dab29989351 100644 --- a/erpnext/agriculture/doctype/agriculture_task/agriculture_task.py +++ b/erpnext/agriculture/doctype/agriculture_task/agriculture_task.py @@ -1,8 +1,6 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2017, Frappe Technologies Pvt. Ltd. and contributors # For license information, please see license.txt -from __future__ import unicode_literals from frappe.model.document import Document diff --git a/erpnext/agriculture/doctype/agriculture_task/test_agriculture_task.py b/erpnext/agriculture/doctype/agriculture_task/test_agriculture_task.py index 2b3c3386972..94d7915d628 100644 --- a/erpnext/agriculture/doctype/agriculture_task/test_agriculture_task.py +++ b/erpnext/agriculture/doctype/agriculture_task/test_agriculture_task.py @@ -1,7 +1,5 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2017, Frappe Technologies Pvt. Ltd. and Contributors # See license.txt -from __future__ import unicode_literals import unittest diff --git a/erpnext/agriculture/doctype/crop/crop.py b/erpnext/agriculture/doctype/crop/crop.py index ef02613d3d9..ed2073cebf8 100644 --- a/erpnext/agriculture/doctype/crop/crop.py +++ b/erpnext/agriculture/doctype/crop/crop.py @@ -1,8 +1,6 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2017, Frappe Technologies Pvt. Ltd. and contributors # For license information, please see license.txt -from __future__ import unicode_literals import frappe from frappe import _ diff --git a/erpnext/agriculture/doctype/crop/crop_dashboard.py b/erpnext/agriculture/doctype/crop/crop_dashboard.py index 02b937a74b2..37cdbb2df52 100644 --- a/erpnext/agriculture/doctype/crop/crop_dashboard.py +++ b/erpnext/agriculture/doctype/crop/crop_dashboard.py @@ -1,5 +1,3 @@ -from __future__ import unicode_literals - from frappe import _ diff --git a/erpnext/agriculture/doctype/crop/test_crop.py b/erpnext/agriculture/doctype/crop/test_crop.py index 1968a04796d..c79a3672199 100644 --- a/erpnext/agriculture/doctype/crop/test_crop.py +++ b/erpnext/agriculture/doctype/crop/test_crop.py @@ -1,7 +1,5 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2017, Frappe Technologies Pvt. Ltd. and Contributors # See license.txt -from __future__ import unicode_literals import unittest diff --git a/erpnext/agriculture/doctype/crop_cycle/crop_cycle.py b/erpnext/agriculture/doctype/crop_cycle/crop_cycle.py index 9000dea913b..43c5bbde82f 100644 --- a/erpnext/agriculture/doctype/crop_cycle/crop_cycle.py +++ b/erpnext/agriculture/doctype/crop_cycle/crop_cycle.py @@ -1,8 +1,6 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2017, Frappe Technologies Pvt. Ltd. and contributors # For license information, please see license.txt -from __future__ import unicode_literals import ast diff --git a/erpnext/agriculture/doctype/crop_cycle/test_crop_cycle.py b/erpnext/agriculture/doctype/crop_cycle/test_crop_cycle.py index 763b4036c3a..e4765a57c0b 100644 --- a/erpnext/agriculture/doctype/crop_cycle/test_crop_cycle.py +++ b/erpnext/agriculture/doctype/crop_cycle/test_crop_cycle.py @@ -1,7 +1,5 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2017, Frappe Technologies Pvt. Ltd. and Contributors # See license.txt -from __future__ import unicode_literals import unittest diff --git a/erpnext/agriculture/doctype/detected_disease/detected_disease.py b/erpnext/agriculture/doctype/detected_disease/detected_disease.py index b73fc32f7fd..e507add7f92 100644 --- a/erpnext/agriculture/doctype/detected_disease/detected_disease.py +++ b/erpnext/agriculture/doctype/detected_disease/detected_disease.py @@ -1,8 +1,6 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2017, Frappe Technologies Pvt. Ltd. and contributors # For license information, please see license.txt -from __future__ import unicode_literals from frappe.model.document import Document diff --git a/erpnext/agriculture/doctype/disease/disease.py b/erpnext/agriculture/doctype/disease/disease.py index e474efe5153..30ab298376a 100644 --- a/erpnext/agriculture/doctype/disease/disease.py +++ b/erpnext/agriculture/doctype/disease/disease.py @@ -1,8 +1,6 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2017, Frappe Technologies Pvt. Ltd. and contributors # For license information, please see license.txt -from __future__ import unicode_literals import frappe from frappe import _ diff --git a/erpnext/agriculture/doctype/disease/test_disease.py b/erpnext/agriculture/doctype/disease/test_disease.py index 1959d1f8112..6a6f1e70a94 100644 --- a/erpnext/agriculture/doctype/disease/test_disease.py +++ b/erpnext/agriculture/doctype/disease/test_disease.py @@ -1,7 +1,5 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2017, Frappe Technologies Pvt. Ltd. and Contributors # See license.txt -from __future__ import unicode_literals import unittest diff --git a/erpnext/agriculture/doctype/fertilizer/fertilizer.py b/erpnext/agriculture/doctype/fertilizer/fertilizer.py index 75c2542b85a..2408302bd18 100644 --- a/erpnext/agriculture/doctype/fertilizer/fertilizer.py +++ b/erpnext/agriculture/doctype/fertilizer/fertilizer.py @@ -1,8 +1,6 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2017, Frappe Technologies Pvt. Ltd. and contributors # For license information, please see license.txt -from __future__ import unicode_literals import frappe from frappe.model.document import Document diff --git a/erpnext/agriculture/doctype/fertilizer/test_fertilizer.py b/erpnext/agriculture/doctype/fertilizer/test_fertilizer.py index c11c61afec2..c8630ef1f87 100644 --- a/erpnext/agriculture/doctype/fertilizer/test_fertilizer.py +++ b/erpnext/agriculture/doctype/fertilizer/test_fertilizer.py @@ -1,7 +1,5 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2017, Frappe Technologies Pvt. Ltd. and Contributors # See license.txt -from __future__ import unicode_literals import unittest diff --git a/erpnext/agriculture/doctype/fertilizer_content/fertilizer_content.py b/erpnext/agriculture/doctype/fertilizer_content/fertilizer_content.py index a050b710107..967c3e02de6 100644 --- a/erpnext/agriculture/doctype/fertilizer_content/fertilizer_content.py +++ b/erpnext/agriculture/doctype/fertilizer_content/fertilizer_content.py @@ -1,8 +1,6 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2017, Frappe Technologies Pvt. Ltd. and contributors # For license information, please see license.txt -from __future__ import unicode_literals from frappe.model.document import Document diff --git a/erpnext/agriculture/doctype/linked_location/linked_location.py b/erpnext/agriculture/doctype/linked_location/linked_location.py index e622e84dc32..e1257f3db16 100644 --- a/erpnext/agriculture/doctype/linked_location/linked_location.py +++ b/erpnext/agriculture/doctype/linked_location/linked_location.py @@ -1,8 +1,6 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2018, Frappe Technologies Pvt. Ltd. and contributors # For license information, please see license.txt -from __future__ import unicode_literals from frappe.model.document import Document diff --git a/erpnext/agriculture/doctype/linked_plant_analysis/linked_plant_analysis.py b/erpnext/agriculture/doctype/linked_plant_analysis/linked_plant_analysis.py index 608bf8c5e3a..0bc04af6406 100644 --- a/erpnext/agriculture/doctype/linked_plant_analysis/linked_plant_analysis.py +++ b/erpnext/agriculture/doctype/linked_plant_analysis/linked_plant_analysis.py @@ -1,8 +1,6 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2017, Frappe Technologies Pvt. Ltd. and contributors # For license information, please see license.txt -from __future__ import unicode_literals from frappe.model.document import Document diff --git a/erpnext/agriculture/doctype/linked_soil_analysis/linked_soil_analysis.py b/erpnext/agriculture/doctype/linked_soil_analysis/linked_soil_analysis.py index 02eb133de91..0d290556bf9 100644 --- a/erpnext/agriculture/doctype/linked_soil_analysis/linked_soil_analysis.py +++ b/erpnext/agriculture/doctype/linked_soil_analysis/linked_soil_analysis.py @@ -1,8 +1,6 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2017, Frappe Technologies Pvt. Ltd. and contributors # For license information, please see license.txt -from __future__ import unicode_literals from frappe.model.document import Document diff --git a/erpnext/agriculture/doctype/linked_soil_texture/linked_soil_texture.py b/erpnext/agriculture/doctype/linked_soil_texture/linked_soil_texture.py index f580e165762..1438853690a 100644 --- a/erpnext/agriculture/doctype/linked_soil_texture/linked_soil_texture.py +++ b/erpnext/agriculture/doctype/linked_soil_texture/linked_soil_texture.py @@ -1,8 +1,6 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2017, Frappe Technologies Pvt. Ltd. and contributors # For license information, please see license.txt -from __future__ import unicode_literals from frappe.model.document import Document diff --git a/erpnext/agriculture/doctype/plant_analysis/plant_analysis.py b/erpnext/agriculture/doctype/plant_analysis/plant_analysis.py index 62382500166..9a939cde0b4 100644 --- a/erpnext/agriculture/doctype/plant_analysis/plant_analysis.py +++ b/erpnext/agriculture/doctype/plant_analysis/plant_analysis.py @@ -1,8 +1,6 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2017, Frappe Technologies Pvt. Ltd. and contributors # For license information, please see license.txt -from __future__ import unicode_literals import frappe from frappe.model.document import Document diff --git a/erpnext/agriculture/doctype/plant_analysis/test_plant_analysis.py b/erpnext/agriculture/doctype/plant_analysis/test_plant_analysis.py index 6b6e8436124..cee241f53ae 100644 --- a/erpnext/agriculture/doctype/plant_analysis/test_plant_analysis.py +++ b/erpnext/agriculture/doctype/plant_analysis/test_plant_analysis.py @@ -1,7 +1,5 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2017, Frappe Technologies Pvt. Ltd. and Contributors # See license.txt -from __future__ import unicode_literals import unittest diff --git a/erpnext/agriculture/doctype/plant_analysis_criteria/plant_analysis_criteria.py b/erpnext/agriculture/doctype/plant_analysis_criteria/plant_analysis_criteria.py index 9f719874ed2..7e6571c4a3d 100644 --- a/erpnext/agriculture/doctype/plant_analysis_criteria/plant_analysis_criteria.py +++ b/erpnext/agriculture/doctype/plant_analysis_criteria/plant_analysis_criteria.py @@ -1,8 +1,6 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2017, Frappe Technologies Pvt. Ltd. and contributors # For license information, please see license.txt -from __future__ import unicode_literals from frappe.model.document import Document diff --git a/erpnext/agriculture/doctype/soil_analysis/soil_analysis.py b/erpnext/agriculture/doctype/soil_analysis/soil_analysis.py index e0c8177e630..03667fbcae9 100644 --- a/erpnext/agriculture/doctype/soil_analysis/soil_analysis.py +++ b/erpnext/agriculture/doctype/soil_analysis/soil_analysis.py @@ -1,8 +1,6 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2017, Frappe Technologies Pvt. Ltd. and contributors # For license information, please see license.txt -from __future__ import unicode_literals import frappe from frappe.model.document import Document diff --git a/erpnext/agriculture/doctype/soil_analysis/test_soil_analysis.py b/erpnext/agriculture/doctype/soil_analysis/test_soil_analysis.py index 24fe0748d38..bb99363ffd9 100644 --- a/erpnext/agriculture/doctype/soil_analysis/test_soil_analysis.py +++ b/erpnext/agriculture/doctype/soil_analysis/test_soil_analysis.py @@ -1,7 +1,5 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2017, Frappe Technologies Pvt. Ltd. and Contributors # See license.txt -from __future__ import unicode_literals import unittest diff --git a/erpnext/agriculture/doctype/soil_analysis_criteria/soil_analysis_criteria.py b/erpnext/agriculture/doctype/soil_analysis_criteria/soil_analysis_criteria.py index 09b917c549a..f5018203287 100644 --- a/erpnext/agriculture/doctype/soil_analysis_criteria/soil_analysis_criteria.py +++ b/erpnext/agriculture/doctype/soil_analysis_criteria/soil_analysis_criteria.py @@ -1,8 +1,6 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2017, Frappe Technologies Pvt. Ltd. and contributors # For license information, please see license.txt -from __future__ import unicode_literals from frappe.model.document import Document diff --git a/erpnext/agriculture/doctype/soil_texture/soil_texture.py b/erpnext/agriculture/doctype/soil_texture/soil_texture.py index 636af77f4f8..b1fc9a063d0 100644 --- a/erpnext/agriculture/doctype/soil_texture/soil_texture.py +++ b/erpnext/agriculture/doctype/soil_texture/soil_texture.py @@ -1,8 +1,6 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2017, Frappe Technologies Pvt. Ltd. and contributors # For license information, please see license.txt -from __future__ import unicode_literals import frappe from frappe import _ diff --git a/erpnext/agriculture/doctype/soil_texture/test_soil_texture.py b/erpnext/agriculture/doctype/soil_texture/test_soil_texture.py index c701eb8f271..45497675cec 100644 --- a/erpnext/agriculture/doctype/soil_texture/test_soil_texture.py +++ b/erpnext/agriculture/doctype/soil_texture/test_soil_texture.py @@ -1,7 +1,5 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2017, Frappe Technologies Pvt. Ltd. and Contributors # See license.txt -from __future__ import unicode_literals import unittest diff --git a/erpnext/agriculture/doctype/soil_texture_criteria/soil_texture_criteria.py b/erpnext/agriculture/doctype/soil_texture_criteria/soil_texture_criteria.py index 9980e8b0cae..92a0cf9aec4 100644 --- a/erpnext/agriculture/doctype/soil_texture_criteria/soil_texture_criteria.py +++ b/erpnext/agriculture/doctype/soil_texture_criteria/soil_texture_criteria.py @@ -1,8 +1,6 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2017, Frappe Technologies Pvt. Ltd. and contributors # For license information, please see license.txt -from __future__ import unicode_literals from frappe.model.document import Document diff --git a/erpnext/agriculture/doctype/water_analysis/test_water_analysis.py b/erpnext/agriculture/doctype/water_analysis/test_water_analysis.py index 5cddeeb1616..ae144ccb210 100644 --- a/erpnext/agriculture/doctype/water_analysis/test_water_analysis.py +++ b/erpnext/agriculture/doctype/water_analysis/test_water_analysis.py @@ -1,7 +1,5 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2017, Frappe Technologies Pvt. Ltd. and Contributors # See license.txt -from __future__ import unicode_literals import unittest diff --git a/erpnext/agriculture/doctype/water_analysis/water_analysis.py b/erpnext/agriculture/doctype/water_analysis/water_analysis.py index 228ae340f20..434acecc6e3 100644 --- a/erpnext/agriculture/doctype/water_analysis/water_analysis.py +++ b/erpnext/agriculture/doctype/water_analysis/water_analysis.py @@ -1,8 +1,6 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2017, Frappe Technologies Pvt. Ltd. and contributors # For license information, please see license.txt -from __future__ import unicode_literals import frappe from frappe import _ diff --git a/erpnext/agriculture/doctype/water_analysis_criteria/water_analysis_criteria.py b/erpnext/agriculture/doctype/water_analysis_criteria/water_analysis_criteria.py index 8771733213c..225c4f6529d 100644 --- a/erpnext/agriculture/doctype/water_analysis_criteria/water_analysis_criteria.py +++ b/erpnext/agriculture/doctype/water_analysis_criteria/water_analysis_criteria.py @@ -1,8 +1,6 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2017, Frappe Technologies Pvt. Ltd. and contributors # For license information, please see license.txt -from __future__ import unicode_literals from frappe.model.document import Document diff --git a/erpnext/agriculture/doctype/weather/test_weather.py b/erpnext/agriculture/doctype/weather/test_weather.py index 1b4bab9a53a..345baa9e99d 100644 --- a/erpnext/agriculture/doctype/weather/test_weather.py +++ b/erpnext/agriculture/doctype/weather/test_weather.py @@ -1,7 +1,5 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2017, Frappe Technologies Pvt. Ltd. and Contributors # See license.txt -from __future__ import unicode_literals import unittest diff --git a/erpnext/agriculture/doctype/weather/weather.py b/erpnext/agriculture/doctype/weather/weather.py index b41964dafda..8750709c564 100644 --- a/erpnext/agriculture/doctype/weather/weather.py +++ b/erpnext/agriculture/doctype/weather/weather.py @@ -1,8 +1,6 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2017, Frappe Technologies Pvt. Ltd. and contributors # For license information, please see license.txt -from __future__ import unicode_literals import frappe from frappe.model.document import Document diff --git a/erpnext/agriculture/doctype/weather_parameter/weather_parameter.py b/erpnext/agriculture/doctype/weather_parameter/weather_parameter.py index 42fcbcb719a..7f02ab39aec 100644 --- a/erpnext/agriculture/doctype/weather_parameter/weather_parameter.py +++ b/erpnext/agriculture/doctype/weather_parameter/weather_parameter.py @@ -1,8 +1,6 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2017, Frappe Technologies Pvt. Ltd. and contributors # For license information, please see license.txt -from __future__ import unicode_literals from frappe.model.document import Document diff --git a/erpnext/agriculture/setup.py b/erpnext/agriculture/setup.py index 75f07be5de2..70931b9ad59 100644 --- a/erpnext/agriculture/setup.py +++ b/erpnext/agriculture/setup.py @@ -1,4 +1,3 @@ -from __future__ import unicode_literals import frappe from frappe import _ from erpnext.setup.utils import insert_record diff --git a/erpnext/agriculture/workspace/agriculture/agriculture.json b/erpnext/agriculture/workspace/agriculture/agriculture.json index 633777eeb70..6714de6d382 100644 --- a/erpnext/agriculture/workspace/agriculture/agriculture.json +++ b/erpnext/agriculture/workspace/agriculture/agriculture.json @@ -1,20 +1,13 @@ { - "category": "", "charts": [], "content": "[{\"type\": \"header\", \"data\": {\"text\": \"Reports & Masters\", \"level\": 4, \"col\": 12}}, {\"type\": \"card\", \"data\": {\"card_name\": \"Crops & Lands\", \"col\": 4}}, {\"type\": \"card\", \"data\": {\"card_name\": \"Analytics\", \"col\": 4}}, {\"type\": \"card\", \"data\": {\"card_name\": \"Diseases & Fertilizers\", \"col\": 4}}]", "creation": "2020-03-02 17:23:34.339274", - "developer_mode_only": 0, - "disable_user_customization": 0, "docstatus": 0, "doctype": "Workspace", - "extends": "", - "extends_another_page": 0, "for_user": "", "hide_custom": 0, "icon": "agriculture", "idx": 0, - "is_default": 0, - "is_standard": 0, "label": "Agriculture", "links": [ { @@ -163,15 +156,12 @@ "type": "Link" } ], - "modified": "2021-08-05 12:15:54.595197", + "modified": "2021-08-05 12:15:54.595198", "modified_by": "Administrator", "module": "Agriculture", "name": "Agriculture", - "onboarding": "", "owner": "Administrator", "parent_page": "", - "pin_to_bottom": 0, - "pin_to_top": 0, "public": 1, "restrict_to_domain": "Agriculture", "roles": [], diff --git a/erpnext/assets/doctype/asset/asset.py b/erpnext/assets/doctype/asset/asset.py index 8ff4f9790aa..c0c437f8d2f 100644 --- a/erpnext/assets/doctype/asset/asset.py +++ b/erpnext/assets/doctype/asset/asset.py @@ -1,8 +1,6 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2016, Frappe Technologies Pvt. Ltd. and contributors # For license information, please see license.txt -from __future__ import unicode_literals import json import math @@ -22,7 +20,6 @@ from frappe.utils import ( nowdate, today, ) -from six import string_types import erpnext from erpnext.accounts.general_ledger import make_reverse_gl_entries @@ -75,12 +72,12 @@ class Asset(AccountsController): if self.is_existing_asset and self.purchase_invoice: frappe.throw(_("Purchase Invoice cannot be made against an existing asset {0}").format(self.name)) - def prepare_depreciation_data(self, date_of_sale=None): + def prepare_depreciation_data(self, date_of_sale=None, date_of_return=None): if self.calculate_depreciation: self.value_after_depreciation = 0 self.set_depreciation_rate() self.make_depreciation_schedule(date_of_sale) - self.set_accumulated_depreciation(date_of_sale) + self.set_accumulated_depreciation(date_of_sale, date_of_return) else: self.finance_books = [] self.value_after_depreciation = (flt(self.gross_purchase_amount) - @@ -140,11 +137,6 @@ class Asset(AccountsController): if self.is_existing_asset: return - docname = self.purchase_receipt or self.purchase_invoice - if docname: - doctype = 'Purchase Receipt' if self.purchase_receipt else 'Purchase Invoice' - date = frappe.db.get_value(doctype, docname, 'posting_date') - if self.available_for_use_date and getdate(self.available_for_use_date) < getdate(self.purchase_date): frappe.throw(_("Available-for-use Date should be after purchase date")) @@ -187,7 +179,7 @@ class Asset(AccountsController): d.precision("rate_of_depreciation")) def make_depreciation_schedule(self, date_of_sale): - if 'Manual' not in [d.depreciation_method for d in self.finance_books] and not self.schedules: + if 'Manual' not in [d.depreciation_method for d in self.finance_books] and not self.get('schedules'): self.schedules = [] if not self.available_for_use_date: @@ -199,7 +191,7 @@ class Asset(AccountsController): start = self.clear_depreciation_schedule() # value_after_depreciation - current Asset value - if d.value_after_depreciation: + if self.docstatus == 1 and d.value_after_depreciation: value_after_depreciation = (flt(d.value_after_depreciation) - flt(self.opening_accumulated_depreciation)) else: @@ -237,13 +229,15 @@ class Asset(AccountsController): depreciation_amount, days, months = self.get_pro_rata_amt(d, depreciation_amount, from_date, date_of_sale) - self.append("schedules", { - "schedule_date": date_of_sale, - "depreciation_amount": depreciation_amount, - "depreciation_method": d.depreciation_method, - "finance_book": d.finance_book, - "finance_book_id": d.idx - }) + if depreciation_amount > 0: + self.append("schedules", { + "schedule_date": date_of_sale, + "depreciation_amount": depreciation_amount, + "depreciation_method": d.depreciation_method, + "finance_book": d.finance_book, + "finance_book_id": d.idx + }) + break # For first row @@ -262,11 +256,15 @@ class Asset(AccountsController): self.to_date = add_months(self.available_for_use_date, n * cint(d.frequency_of_depreciation)) + depreciation_amount_without_pro_rata = depreciation_amount + depreciation_amount, days, months = self.get_pro_rata_amt(d, depreciation_amount, schedule_date, self.to_date) - monthly_schedule_date = add_months(schedule_date, 1) + depreciation_amount = self.get_adjusted_depreciation_amount(depreciation_amount_without_pro_rata, + depreciation_amount, d.finance_book) + monthly_schedule_date = add_months(schedule_date, 1) schedule_date = add_days(schedule_date, days) last_schedule_date = schedule_date @@ -394,10 +392,6 @@ class Asset(AccountsController): if cint(self.number_of_depreciations_booked) > cint(row.total_number_of_depreciations): frappe.throw(_("Number of Depreciations Booked cannot be greater than Total Number of Depreciations")) - if row.depreciation_start_date and getdate(row.depreciation_start_date) < getdate(nowdate()): - frappe.msgprint(_("Depreciation Row {0}: Depreciation Start Date is entered as past date") - .format(row.idx), title=_('Warning'), indicator='red') - if row.depreciation_start_date and getdate(row.depreciation_start_date) < getdate(self.purchase_date): frappe.throw(_("Depreciation Row {0}: Next Depreciation Date cannot be before Purchase Date") .format(row.idx)) @@ -406,7 +400,28 @@ class Asset(AccountsController): frappe.throw(_("Depreciation Row {0}: Next Depreciation Date cannot be before Available-for-use Date") .format(row.idx)) - def set_accumulated_depreciation(self, date_of_sale=None, ignore_booked_entry = False): + # to ensure that final accumulated depreciation amount is accurate + def get_adjusted_depreciation_amount(self, depreciation_amount_without_pro_rata, depreciation_amount_for_last_row, finance_book): + depreciation_amount_for_first_row = self.get_depreciation_amount_for_first_row(finance_book) + + if depreciation_amount_for_first_row + depreciation_amount_for_last_row != depreciation_amount_without_pro_rata: + depreciation_amount_for_last_row = depreciation_amount_without_pro_rata - depreciation_amount_for_first_row + + return depreciation_amount_for_last_row + + def get_depreciation_amount_for_first_row(self, finance_book): + if self.has_only_one_finance_book(): + return self.schedules[0].depreciation_amount + else: + for schedule in self.schedules: + if schedule.finance_book == finance_book: + return schedule.depreciation_amount + + def has_only_one_finance_book(self): + if len(self.finance_books) == 1: + return True + + def set_accumulated_depreciation(self, date_of_sale=None, date_of_return=None, ignore_booked_entry = False): straight_line_idx = [d.idx for d in self.get("schedules") if d.depreciation_method == 'Straight Line'] finance_books = [] @@ -423,7 +438,7 @@ class Asset(AccountsController): value_after_depreciation -= flt(depreciation_amount) # for the last row, if depreciation method = Straight Line - if straight_line_idx and i == max(straight_line_idx) - 1 and not date_of_sale: + if straight_line_idx and i == max(straight_line_idx) - 1 and not date_of_sale and not date_of_return: book = self.get('finance_books')[cint(d.finance_book_id) - 1] depreciation_amount += flt(value_after_depreciation - flt(book.expected_value_after_useful_life), d.precision("depreciation_amount")) @@ -444,9 +459,10 @@ class Asset(AccountsController): if accumulated_depreciation_after_full_schedule: accumulated_depreciation_after_full_schedule = max(accumulated_depreciation_after_full_schedule) - asset_value_after_full_schedule = flt(flt(self.gross_purchase_amount) - - flt(accumulated_depreciation_after_full_schedule), - self.precision('gross_purchase_amount')) + asset_value_after_full_schedule = flt( + flt(self.gross_purchase_amount) - + flt(self.opening_accumulated_depreciation) - + flt(accumulated_depreciation_after_full_schedule), self.precision('gross_purchase_amount')) if (row.expected_value_after_useful_life and row.expected_value_after_useful_life < asset_value_after_full_schedule): @@ -608,7 +624,7 @@ class Asset(AccountsController): @frappe.whitelist() def get_depreciation_rate(self, args, on_validate=False): - if isinstance(args, string_types): + if isinstance(args, str): args = json.loads(args) float_precision = cint(frappe.db.get_default("float_precision")) or 2 @@ -803,9 +819,7 @@ def make_journal_entry(asset_name): def make_asset_movement(assets, purpose=None): import json - from six import string_types - - if isinstance(assets, string_types): + if isinstance(assets, str): assets = json.loads(assets) if len(assets) == 0: @@ -841,7 +855,7 @@ def get_depreciation_amount(asset, depreciable_value, row): if row.depreciation_method in ("Straight Line", "Manual"): # if the Depreciation Schedule is being prepared for the first time if not asset.flags.increase_in_asset_life: - depreciation_amount = (flt(row.value_after_depreciation) - + depreciation_amount = (flt(asset.gross_purchase_amount) - flt(asset.opening_accumulated_depreciation) - flt(row.expected_value_after_useful_life)) / depreciation_left # if the Depreciation Schedule is being modified after Asset Repair diff --git a/erpnext/assets/doctype/asset/asset_dashboard.py b/erpnext/assets/doctype/asset/asset_dashboard.py index cd04e1d8f04..00d08473d66 100644 --- a/erpnext/assets/doctype/asset/asset_dashboard.py +++ b/erpnext/assets/doctype/asset/asset_dashboard.py @@ -1,6 +1,3 @@ -from __future__ import unicode_literals - - def get_data(): return { 'non_standard_fieldnames': { diff --git a/erpnext/assets/doctype/asset/depreciation.py b/erpnext/assets/doctype/asset/depreciation.py index 609791012a2..ca10b1db19a 100644 --- a/erpnext/assets/doctype/asset/depreciation.py +++ b/erpnext/assets/doctype/asset/depreciation.py @@ -1,8 +1,6 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2016, Frappe Technologies Pvt. Ltd. and contributors # For license information, please see license.txt -from __future__ import unicode_literals import frappe from frappe import _ diff --git a/erpnext/assets/doctype/asset/test_asset.py b/erpnext/assets/doctype/asset/test_asset.py index 4cc9be5b05d..d1d4527ec70 100644 --- a/erpnext/assets/doctype/asset/test_asset.py +++ b/erpnext/assets/doctype/asset/test_asset.py @@ -1,7 +1,5 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors # See license.txt -from __future__ import unicode_literals import unittest @@ -21,12 +19,72 @@ from erpnext.stock.doctype.purchase_receipt.purchase_receipt import ( from erpnext.stock.doctype.purchase_receipt.test_purchase_receipt import make_purchase_receipt -class TestAsset(unittest.TestCase): - def setUp(self): +class AssetSetup(unittest.TestCase): + @classmethod + def setUpClass(cls): set_depreciation_settings_in_company() create_asset_data() + enable_cwip_accounting("Computers") + make_purchase_receipt(item_code="Macbook Pro", qty=1, rate=100000.0, location="Test Location") frappe.db.sql("delete from `tabTax Rule`") + @classmethod + def tearDownClass(cls): + frappe.db.rollback() + +class TestAsset(AssetSetup): + def test_asset_category_is_fetched(self): + """Tests if the Item's Asset Category value is assigned to the Asset, if the field is empty.""" + + asset = create_asset(item_code="Macbook Pro", do_not_save=1) + asset.asset_category = None + asset.save() + + self.assertEqual(asset.asset_category, "Computers") + + def test_gross_purchase_amount_is_mandatory(self): + asset = create_asset(item_code="Macbook Pro", do_not_save=1) + asset.gross_purchase_amount = 0 + + self.assertRaises(frappe.MandatoryError, asset.save) + + def test_pr_or_pi_mandatory_if_not_existing_asset(self): + """Tests if either PI or PR is present if CWIP is enabled and is_existing_asset=0.""" + + asset = create_asset(item_code="Macbook Pro", do_not_save=1) + asset.is_existing_asset=0 + + self.assertRaises(frappe.ValidationError, asset.save) + + def test_available_for_use_date_is_after_purchase_date(self): + asset = create_asset(item_code="Macbook Pro", calculate_depreciation=1, do_not_save=1) + asset.is_existing_asset = 0 + asset.purchase_date = getdate("2021-10-10") + asset.available_for_use_date = getdate("2021-10-1") + + self.assertRaises(frappe.ValidationError, asset.save) + + def test_item_exists(self): + asset = create_asset(item_code="MacBook", do_not_save=1) + + self.assertRaises(frappe.DoesNotExistError, asset.save) + + def test_validate_item(self): + asset = create_asset(item_code="MacBook Pro", do_not_save=1) + item = frappe.get_doc("Item", "MacBook Pro") + + item.disabled = 1 + item.save() + self.assertRaises(frappe.ValidationError, asset.save) + item.disabled = 0 + + item.is_fixed_asset = 0 + self.assertRaises(frappe.ValidationError, asset.save) + item.is_fixed_asset = 1 + + item.is_stock_item = 1 + self.assertRaises(frappe.ValidationError, asset.save) + def test_purchase_asset(self): pr = make_purchase_receipt(item_code="Macbook Pro", qty=1, rate=100000.0, location="Test Location") @@ -89,302 +147,16 @@ class TestAsset(unittest.TestCase): doc.set_missing_values() self.assertEqual(doc.items[0].is_fixed_asset, 1) - def test_schedule_for_straight_line_method(self): - pr = make_purchase_receipt(item_code="Macbook Pro", - qty=1, rate=100000.0, location="Test Location") - - asset_name = frappe.db.get_value("Asset", {"purchase_receipt": pr.name}, 'name') - asset = frappe.get_doc('Asset', asset_name) - asset.calculate_depreciation = 1 - asset.available_for_use_date = '2030-01-01' - asset.purchase_date = '2030-01-01' - - asset.append("finance_books", { - "expected_value_after_useful_life": 10000, - "depreciation_method": "Straight Line", - "total_number_of_depreciations": 3, - "frequency_of_depreciation": 12, - "depreciation_start_date": "2030-12-31" - }) - asset.save() - - self.assertEqual(asset.status, "Draft") - expected_schedules = [ - ["2030-12-31", 30000.00, 30000.00], - ["2031-12-31", 30000.00, 60000.00], - ["2032-12-31", 30000.00, 90000.00] - ] - - schedules = [[cstr(d.schedule_date), d.depreciation_amount, d.accumulated_depreciation_amount] - for d in asset.get("schedules")] - - self.assertEqual(schedules, expected_schedules) - - def test_schedule_for_straight_line_method_for_existing_asset(self): - create_asset(is_existing_asset=1) - asset = frappe.get_doc("Asset", {"asset_name": "Macbook Pro 1"}) - asset.calculate_depreciation = 1 - asset.number_of_depreciations_booked = 1 - asset.opening_accumulated_depreciation = 40000 - asset.available_for_use_date = "2030-06-06" - asset.append("finance_books", { - "expected_value_after_useful_life": 10000, - "depreciation_method": "Straight Line", - "total_number_of_depreciations": 3, - "frequency_of_depreciation": 12, - "depreciation_start_date": "2030-12-31" - }) - self.assertEqual(asset.status, "Draft") - asset.save() - expected_schedules = [ - ["2030-12-31", 14246.58, 54246.58], - ["2031-12-31", 25000.00, 79246.58], - ["2032-06-06", 10753.42, 90000.00] - ] - schedules = [[cstr(d.schedule_date), flt(d.depreciation_amount, 2), d.accumulated_depreciation_amount] - for d in asset.get("schedules")] - - self.assertEqual(schedules, expected_schedules) - - def test_schedule_for_double_declining_method(self): - pr = make_purchase_receipt(item_code="Macbook Pro", - qty=1, rate=100000.0, location="Test Location") - - asset_name = frappe.db.get_value("Asset", {"purchase_receipt": pr.name}, 'name') - asset = frappe.get_doc('Asset', asset_name) - asset.calculate_depreciation = 1 - asset.available_for_use_date = '2030-01-01' - asset.purchase_date = '2030-01-01' - asset.append("finance_books", { - "expected_value_after_useful_life": 10000, - "depreciation_method": "Double Declining Balance", - "total_number_of_depreciations": 3, - "frequency_of_depreciation": 12, - "depreciation_start_date": '2030-12-31' - }) - asset.save() - self.assertEqual(asset.status, "Draft") - - expected_schedules = [ - ['2030-12-31', 66667.00, 66667.00], - ['2031-12-31', 22222.11, 88889.11], - ['2032-12-31', 1110.89, 90000.0] - ] - - schedules = [[cstr(d.schedule_date), d.depreciation_amount, d.accumulated_depreciation_amount] - for d in asset.get("schedules")] - - self.assertEqual(schedules, expected_schedules) - - def test_schedule_for_double_declining_method_for_existing_asset(self): - create_asset(is_existing_asset = 1) - asset = frappe.get_doc("Asset", {"asset_name": "Macbook Pro 1"}) - asset.calculate_depreciation = 1 - asset.is_existing_asset = 1 - asset.number_of_depreciations_booked = 1 - asset.opening_accumulated_depreciation = 50000 - asset.available_for_use_date = '2030-01-01' - asset.purchase_date = '2029-11-30' - asset.append("finance_books", { - "expected_value_after_useful_life": 10000, - "depreciation_method": "Double Declining Balance", - "total_number_of_depreciations": 3, - "frequency_of_depreciation": 12, - "depreciation_start_date": "2030-12-31" - }) - asset.save() - self.assertEqual(asset.status, "Draft") - - expected_schedules = [ - ["2030-12-31", 33333.50, 83333.50], - ["2031-12-31", 6666.50, 90000.0] - ] - - schedules = [[cstr(d.schedule_date), d.depreciation_amount, d.accumulated_depreciation_amount] - for d in asset.get("schedules")] - - self.assertEqual(schedules, expected_schedules) - - def test_schedule_for_prorated_straight_line_method(self): - pr = make_purchase_receipt(item_code="Macbook Pro", - qty=1, rate=100000.0, location="Test Location") - - asset_name = frappe.db.get_value("Asset", {"purchase_receipt": pr.name}, 'name') - asset = frappe.get_doc('Asset', asset_name) - asset.calculate_depreciation = 1 - asset.purchase_date = '2030-01-30' - asset.is_existing_asset = 0 - asset.available_for_use_date = "2030-01-30" - asset.append("finance_books", { - "expected_value_after_useful_life": 10000, - "depreciation_method": "Straight Line", - "total_number_of_depreciations": 3, - "frequency_of_depreciation": 12, - "depreciation_start_date": "2030-12-31" - }) - - asset.save() - - expected_schedules = [ - ["2030-12-31", 27534.25, 27534.25], - ["2031-12-31", 30000.0, 57534.25], - ["2032-12-31", 30000.0, 87534.25], - ["2033-01-30", 2465.75, 90000.0] - ] - - schedules = [[cstr(d.schedule_date), flt(d.depreciation_amount, 2), flt(d.accumulated_depreciation_amount, 2)] - for d in asset.get("schedules")] - - self.assertEqual(schedules, expected_schedules) - - def test_depreciation(self): - pr = make_purchase_receipt(item_code="Macbook Pro", - qty=1, rate=100000.0, location="Test Location") - - asset_name = frappe.db.get_value("Asset", {"purchase_receipt": pr.name}, 'name') - asset = frappe.get_doc('Asset', asset_name) - asset.calculate_depreciation = 1 - asset.purchase_date = '2020-01-30' - asset.available_for_use_date = "2020-01-30" - asset.append("finance_books", { - "expected_value_after_useful_life": 10000, - "depreciation_method": "Straight Line", - "total_number_of_depreciations": 3, - "frequency_of_depreciation": 10, - "depreciation_start_date": "2020-12-31" - }) - asset.submit() - asset.load_from_db() - self.assertEqual(asset.status, "Submitted") - - frappe.db.set_value("Company", "_Test Company", "series_for_depreciation_entry", "DEPR-") - post_depreciation_entries(date="2021-01-01") - asset.load_from_db() - - # check depreciation entry series - self.assertEqual(asset.get("schedules")[0].journal_entry[:4], "DEPR") - - expected_gle = ( - ("_Test Accumulated Depreciations - _TC", 0.0, 30000.0), - ("_Test Depreciations - _TC", 30000.0, 0.0) - ) - - gle = frappe.db.sql("""select account, debit, credit from `tabGL Entry` - where against_voucher_type='Asset' and against_voucher = %s - order by account""", asset.name) - - self.assertEqual(gle, expected_gle) - self.assertEqual(asset.get("value_after_depreciation"), 0) - - def test_depreciation_entry_for_wdv_without_pro_rata(self): - pr = make_purchase_receipt(item_code="Macbook Pro", - qty=1, rate=8000.0, location="Test Location") - - asset_name = frappe.db.get_value("Asset", {"purchase_receipt": pr.name}, 'name') - asset = frappe.get_doc('Asset', asset_name) - asset.calculate_depreciation = 1 - asset.available_for_use_date = '2030-01-01' - asset.purchase_date = '2030-01-01' - asset.append("finance_books", { - "expected_value_after_useful_life": 1000, - "depreciation_method": "Written Down Value", - "total_number_of_depreciations": 3, - "frequency_of_depreciation": 12, - "depreciation_start_date": "2030-12-31" - }) - asset.save(ignore_permissions=True) - - self.assertEqual(asset.finance_books[0].rate_of_depreciation, 50.0) - - expected_schedules = [ - ["2030-12-31", 4000.00, 4000.00], - ["2031-12-31", 2000.00, 6000.00], - ["2032-12-31", 1000.00, 7000.0], - ] - - schedules = [[cstr(d.schedule_date), flt(d.depreciation_amount, 2), flt(d.accumulated_depreciation_amount, 2)] - for d in asset.get("schedules")] - - self.assertEqual(schedules, expected_schedules) - - def test_pro_rata_depreciation_entry_for_wdv(self): - pr = make_purchase_receipt(item_code="Macbook Pro", - qty=1, rate=8000.0, location="Test Location") - - asset_name = frappe.db.get_value("Asset", {"purchase_receipt": pr.name}, 'name') - asset = frappe.get_doc('Asset', asset_name) - asset.calculate_depreciation = 1 - asset.available_for_use_date = '2030-06-06' - asset.purchase_date = '2030-01-01' - asset.append("finance_books", { - "expected_value_after_useful_life": 1000, - "depreciation_method": "Written Down Value", - "total_number_of_depreciations": 3, - "frequency_of_depreciation": 12, - "depreciation_start_date": "2030-12-31" - }) - asset.save(ignore_permissions=True) - - self.assertEqual(asset.finance_books[0].rate_of_depreciation, 50.0) - - expected_schedules = [ - ["2030-12-31", 2279.45, 2279.45], - ["2031-12-31", 2860.28, 5139.73], - ["2032-12-31", 1430.14, 6569.87], - ["2033-06-06", 430.13, 7000.0], - ] - - schedules = [[cstr(d.schedule_date), flt(d.depreciation_amount, 2), flt(d.accumulated_depreciation_amount, 2)] - for d in asset.get("schedules")] - - self.assertEqual(schedules, expected_schedules) - - def test_depreciation_entry_cancellation(self): - pr = make_purchase_receipt(item_code="Macbook Pro", - qty=1, rate=100000.0, location="Test Location") - - asset_name = frappe.db.get_value("Asset", {"purchase_receipt": pr.name}, 'name') - asset = frappe.get_doc('Asset', asset_name) - asset.calculate_depreciation = 1 - asset.available_for_use_date = '2020-06-06' - asset.purchase_date = '2020-06-06' - asset.append("finance_books", { - "expected_value_after_useful_life": 10000, - "depreciation_method": "Straight Line", - "total_number_of_depreciations": 3, - "frequency_of_depreciation": 10, - "depreciation_start_date": "2020-12-31" - }) - asset.submit() - post_depreciation_entries(date="2021-01-01") - - asset.load_from_db() - - # cancel depreciation entry - depr_entry = asset.get("schedules")[0].journal_entry - self.assertTrue(depr_entry) - frappe.get_doc("Journal Entry", depr_entry).cancel() - - asset.load_from_db() - depr_entry = asset.get("schedules")[0].journal_entry - self.assertFalse(depr_entry) - def test_scrap_asset(self): - pr = make_purchase_receipt(item_code="Macbook Pro", - qty=1, rate=100000.0, location="Test Location") - - asset_name = frappe.db.get_value("Asset", {"purchase_receipt": pr.name}, 'name') - asset = frappe.get_doc('Asset', asset_name) - asset.calculate_depreciation = 1 - asset.available_for_use_date = '2020-01-01' - asset.purchase_date = '2020-01-01' - asset.append("finance_books", { - "expected_value_after_useful_life": 10000, - "depreciation_method": "Straight Line", - "total_number_of_depreciations": 10, - "frequency_of_depreciation": 1 - }) - asset.submit() + asset = create_asset( + calculate_depreciation = 1, + available_for_use_date = '2020-01-01', + purchase_date = '2020-01-01', + expected_value_after_useful_life = 10000, + total_number_of_depreciations = 10, + frequency_of_depreciation = 1, + submit = 1 + ) post_depreciation_entries(date=add_months('2020-01-01', 4)) @@ -411,23 +183,18 @@ class TestAsset(unittest.TestCase): self.assertFalse(asset.journal_entry_for_scrap) self.assertEqual(asset.status, "Partially Depreciated") - def test_asset_sale(self): - pr = make_purchase_receipt(item_code="Macbook Pro", - qty=1, rate=100000.0, location="Test Location") + def test_gle_made_by_asset_sale(self): + asset = create_asset( + calculate_depreciation = 1, + available_for_use_date = '2020-06-06', + purchase_date = '2020-01-01', + expected_value_after_useful_life = 10000, + total_number_of_depreciations = 3, + frequency_of_depreciation = 10, + depreciation_start_date = '2020-12-31', + submit = 1 + ) - asset_name = frappe.db.get_value("Asset", {"purchase_receipt": pr.name}, 'name') - asset = frappe.get_doc('Asset', asset_name) - asset.calculate_depreciation = 1 - asset.available_for_use_date = '2020-06-06' - asset.purchase_date = '2020-06-06' - asset.append("finance_books", { - "expected_value_after_useful_life": 10000, - "depreciation_method": "Straight Line", - "total_number_of_depreciations": 3, - "frequency_of_depreciation": 10, - "depreciation_start_date": "2020-12-31" - }) - asset.submit() post_depreciation_entries(date="2021-01-01") si = make_sales_invoice(asset=asset.name, item_code="Macbook Pro", company="_Test Company") @@ -455,30 +222,14 @@ class TestAsset(unittest.TestCase): si.cancel() self.assertEqual(frappe.db.get_value("Asset", asset.name, "status"), "Partially Depreciated") - def test_asset_expected_value_after_useful_life(self): + def test_expense_head(self): pr = make_purchase_receipt(item_code="Macbook Pro", - qty=1, rate=100000.0, location="Test Location") + qty=2, rate=200000.0, location="Test Location") + doc = make_invoice(pr.name) - asset_name = frappe.db.get_value("Asset", {"purchase_receipt": pr.name}, 'name') - asset = frappe.get_doc('Asset', asset_name) - asset.calculate_depreciation = 1 - asset.available_for_use_date = '2020-06-06' - asset.purchase_date = '2020-06-06' - asset.append("finance_books", { - "expected_value_after_useful_life": 10000, - "depreciation_method": "Straight Line", - "total_number_of_depreciations": 3, - "frequency_of_depreciation": 10 - }) - asset.save() - accumulated_depreciation_after_full_schedule = \ - max(d.accumulated_depreciation_amount for d in asset.get("schedules")) - - asset_value_after_full_schedule = (flt(asset.gross_purchase_amount) - - flt(accumulated_depreciation_after_full_schedule)) - - self.assertTrue(asset.finance_books[0].expected_value_after_useful_life >= asset_value_after_full_schedule) + self.assertEqual('Asset Received But Not Billed - _TC', doc.items[0].expense_account) + # CWIP: Capital Work In Progress def test_cwip_accounting(self): pr = make_purchase_receipt(item_code="Macbook Pro", qty=1, rate=5000, do_not_submit=True, location="Test Location") @@ -561,14 +312,6 @@ class TestAsset(unittest.TestCase): self.assertEqual(gle, expected_gle) - def test_expense_head(self): - pr = make_purchase_receipt(item_code="Macbook Pro", - qty=2, rate=200000.0, location="Test Location") - - doc = make_invoice(pr.name) - - self.assertEqual('Asset Received But Not Billed - _TC', doc.items[0].expense_account) - def test_asset_cwip_toggling_cases(self): cwip = frappe.db.get_value("Asset Category", "Computers", "enable_cwip_accounting") name = frappe.db.get_value("Asset Category Account", filters={"parent": "Computers"}, fieldname=["name"]) @@ -637,35 +380,211 @@ class TestAsset(unittest.TestCase): frappe.db.set_value("Asset Category Account", name, "capital_work_in_progress_account", cwip_acc) frappe.db.get_value("Company", "_Test Company", "capital_work_in_progress_account", cwip_acc) +class TestDepreciationMethods(AssetSetup): + def test_schedule_for_straight_line_method(self): + asset = create_asset( + calculate_depreciation = 1, + available_for_use_date = "2030-01-01", + purchase_date = "2030-01-01", + expected_value_after_useful_life = 10000, + depreciation_start_date = "2030-12-31", + total_number_of_depreciations = 3, + frequency_of_depreciation = 12 + ) + + self.assertEqual(asset.status, "Draft") + expected_schedules = [ + ["2030-12-31", 30000.00, 30000.00], + ["2031-12-31", 30000.00, 60000.00], + ["2032-12-31", 30000.00, 90000.00] + ] + + schedules = [[cstr(d.schedule_date), d.depreciation_amount, d.accumulated_depreciation_amount] + for d in asset.get("schedules")] + + self.assertEqual(schedules, expected_schedules) + + def test_schedule_for_straight_line_method_for_existing_asset(self): + asset = create_asset( + calculate_depreciation = 1, + available_for_use_date = "2030-06-06", + is_existing_asset = 1, + number_of_depreciations_booked = 1, + opening_accumulated_depreciation = 40000, + expected_value_after_useful_life = 10000, + depreciation_start_date = "2030-12-31", + total_number_of_depreciations = 3, + frequency_of_depreciation = 12 + ) + + self.assertEqual(asset.status, "Draft") + expected_schedules = [ + ["2030-12-31", 14246.58, 54246.58], + ["2031-12-31", 25000.00, 79246.58], + ["2032-06-06", 10753.42, 90000.00] + ] + schedules = [[cstr(d.schedule_date), flt(d.depreciation_amount, 2), d.accumulated_depreciation_amount] + for d in asset.get("schedules")] + + self.assertEqual(schedules, expected_schedules) + + def test_schedule_for_double_declining_method(self): + asset = create_asset( + calculate_depreciation = 1, + available_for_use_date = "2030-01-01", + purchase_date = "2030-01-01", + depreciation_method = "Double Declining Balance", + expected_value_after_useful_life = 10000, + depreciation_start_date = "2030-12-31", + total_number_of_depreciations = 3, + frequency_of_depreciation = 12 + ) + + self.assertEqual(asset.status, "Draft") + + expected_schedules = [ + ['2030-12-31', 66667.00, 66667.00], + ['2031-12-31', 22222.11, 88889.11], + ['2032-12-31', 1110.89, 90000.0] + ] + + schedules = [[cstr(d.schedule_date), d.depreciation_amount, d.accumulated_depreciation_amount] + for d in asset.get("schedules")] + + self.assertEqual(schedules, expected_schedules) + + def test_schedule_for_double_declining_method_for_existing_asset(self): + asset = create_asset( + calculate_depreciation = 1, + available_for_use_date = "2030-01-01", + is_existing_asset = 1, + depreciation_method = "Double Declining Balance", + number_of_depreciations_booked = 1, + opening_accumulated_depreciation = 50000, + expected_value_after_useful_life = 10000, + depreciation_start_date = "2030-12-31", + total_number_of_depreciations = 3, + frequency_of_depreciation = 12 + ) + + self.assertEqual(asset.status, "Draft") + + expected_schedules = [ + ["2030-12-31", 33333.50, 83333.50], + ["2031-12-31", 6666.50, 90000.0] + ] + + schedules = [[cstr(d.schedule_date), d.depreciation_amount, d.accumulated_depreciation_amount] + for d in asset.get("schedules")] + + self.assertEqual(schedules, expected_schedules) + + def test_schedule_for_prorated_straight_line_method(self): + asset = create_asset( + calculate_depreciation = 1, + available_for_use_date = "2030-01-30", + purchase_date = "2030-01-30", + depreciation_method = "Straight Line", + expected_value_after_useful_life = 10000, + depreciation_start_date = "2030-12-31", + total_number_of_depreciations = 3, + frequency_of_depreciation = 12 + ) + + expected_schedules = [ + ["2030-12-31", 27534.25, 27534.25], + ["2031-12-31", 30000.0, 57534.25], + ["2032-12-31", 30000.0, 87534.25], + ["2033-01-30", 2465.75, 90000.0] + ] + + schedules = [[cstr(d.schedule_date), flt(d.depreciation_amount, 2), flt(d.accumulated_depreciation_amount, 2)] + for d in asset.get("schedules")] + + self.assertEqual(schedules, expected_schedules) + + # WDV: Written Down Value method + def test_depreciation_entry_for_wdv_without_pro_rata(self): + asset = create_asset( + calculate_depreciation = 1, + available_for_use_date = "2030-01-01", + purchase_date = "2030-01-01", + depreciation_method = "Written Down Value", + expected_value_after_useful_life = 12500, + depreciation_start_date = "2030-12-31", + total_number_of_depreciations = 3, + frequency_of_depreciation = 12 + ) + + self.assertEqual(asset.finance_books[0].rate_of_depreciation, 50.0) + + expected_schedules = [ + ["2030-12-31", 50000.0, 50000.0], + ["2031-12-31", 25000.0, 75000.0], + ["2032-12-31", 12500.0, 87500.0], + ] + + schedules = [[cstr(d.schedule_date), flt(d.depreciation_amount, 2), flt(d.accumulated_depreciation_amount, 2)] + for d in asset.get("schedules")] + + self.assertEqual(schedules, expected_schedules) + + # WDV: Written Down Value method + def test_pro_rata_depreciation_entry_for_wdv(self): + asset = create_asset( + calculate_depreciation = 1, + available_for_use_date = "2030-06-06", + purchase_date = "2030-01-01", + depreciation_method = "Written Down Value", + expected_value_after_useful_life = 12500, + depreciation_start_date = "2030-12-31", + total_number_of_depreciations = 3, + frequency_of_depreciation = 12 + ) + + self.assertEqual(asset.finance_books[0].rate_of_depreciation, 50.0) + + expected_schedules = [ + ["2030-12-31", 28493.15, 28493.15], + ["2031-12-31", 35753.43, 64246.58], + ["2032-12-31", 17876.71, 82123.29], + ["2033-06-06", 5376.71, 87500.0] + ] + + schedules = [[cstr(d.schedule_date), flt(d.depreciation_amount, 2), flt(d.accumulated_depreciation_amount, 2)] + for d in asset.get("schedules")] + + self.assertEqual(schedules, expected_schedules) + def test_discounted_wdv_depreciation_rate_for_indian_region(self): # set indian company company_flag = frappe.flags.company frappe.flags.company = "_Test Company" - pr = make_purchase_receipt(item_code="Macbook Pro", - qty=1, rate=8000.0, location="Test Location") + finance_book = frappe.new_doc("Finance Book") + finance_book.finance_book_name = "Income Tax" + finance_book.for_income_tax = 1 + finance_book.insert(ignore_if_duplicate = True) - asset_name = frappe.db.get_value("Asset", {"purchase_receipt": pr.name}, 'name') - asset = frappe.get_doc('Asset', asset_name) - asset.calculate_depreciation = 1 - asset.available_for_use_date = '2030-07-12' - asset.purchase_date = '2030-01-01' - asset.append("finance_books", { - "expected_value_after_useful_life": 1000, - "depreciation_method": "Written Down Value", - "total_number_of_depreciations": 3, - "frequency_of_depreciation": 12, - "depreciation_start_date": "2030-12-31" - }) - asset.save(ignore_permissions=True) + asset = create_asset( + calculate_depreciation = 1, + available_for_use_date = "2030-07-12", + purchase_date = "2030-01-01", + finance_book = finance_book.name, + depreciation_method = "Written Down Value", + expected_value_after_useful_life = 12500, + depreciation_start_date = "2030-12-31", + total_number_of_depreciations = 3, + frequency_of_depreciation = 12 + ) self.assertEqual(asset.finance_books[0].rate_of_depreciation, 50.0) expected_schedules = [ - ["2030-12-31", 942.47, 942.47], - ["2031-12-31", 3528.77, 4471.24], - ["2032-12-31", 1764.38, 6235.62], - ["2033-07-12", 764.38, 7000.00] + ["2030-12-31", 11780.82, 11780.82], + ["2031-12-31", 44109.59, 55890.41], + ["2032-12-31", 22054.8, 77945.21], + ["2033-07-12", 9554.79, 87500.0] ] schedules = [[cstr(d.schedule_date), flt(d.depreciation_amount, 2), flt(d.accumulated_depreciation_amount, 2)] @@ -676,6 +595,400 @@ class TestAsset(unittest.TestCase): # reset indian company frappe.flags.company = company_flag +class TestDepreciationBasics(AssetSetup): + def test_depreciation_without_pro_rata(self): + asset = create_asset( + item_code = "Macbook Pro", + calculate_depreciation = 1, + available_for_use_date = getdate("2019-12-31"), + total_number_of_depreciations = 3, + expected_value_after_useful_life = 10000, + depreciation_start_date = getdate("2020-12-31"), + submit = 1 + ) + + expected_values = [ + ["2020-12-31", 30000, 30000], + ["2021-12-31", 30000, 60000], + ["2022-12-31", 30000, 90000] + ] + + for i, schedule in enumerate(asset.schedules): + self.assertEqual(getdate(expected_values[i][0]), schedule.schedule_date) + self.assertEqual(expected_values[i][1], schedule.depreciation_amount) + self.assertEqual(expected_values[i][2], schedule.accumulated_depreciation_amount) + + def test_depreciation_with_pro_rata(self): + asset = create_asset( + item_code = "Macbook Pro", + calculate_depreciation = 1, + available_for_use_date = getdate("2019-12-31"), + total_number_of_depreciations = 3, + expected_value_after_useful_life = 10000, + depreciation_start_date = getdate("2020-07-01"), + submit = 1 + ) + + expected_values = [ + ["2020-07-01", 15000, 15000], + ["2021-07-01", 30000, 45000], + ["2022-07-01", 30000, 75000], + ["2022-12-31", 15000, 90000] + ] + + for i, schedule in enumerate(asset.schedules): + self.assertEqual(getdate(expected_values[i][0]), schedule.schedule_date) + self.assertEqual(expected_values[i][1], schedule.depreciation_amount) + self.assertEqual(expected_values[i][2], schedule.accumulated_depreciation_amount) + + def test_get_depreciation_amount(self): + """Tests if get_depreciation_amount() returns the right value.""" + + from erpnext.assets.doctype.asset.asset import get_depreciation_amount + + asset = create_asset( + item_code = "Macbook Pro", + available_for_use_date = "2019-12-31" + ) + + asset.calculate_depreciation = 1 + asset.append("finance_books", { + "depreciation_method": "Straight Line", + "frequency_of_depreciation": 12, + "total_number_of_depreciations": 3, + "expected_value_after_useful_life": 10000, + "depreciation_start_date": "2020-12-31" + }) + + depreciation_amount = get_depreciation_amount(asset, 100000, asset.finance_books[0]) + self.assertEqual(depreciation_amount, 30000) + + def test_make_depreciation_schedule(self): + """Tests if make_depreciation_schedule() returns the right values.""" + + asset = create_asset( + item_code = "Macbook Pro", + calculate_depreciation = 1, + available_for_use_date = "2019-12-31", + depreciation_method = "Straight Line", + frequency_of_depreciation = 12, + total_number_of_depreciations = 3, + expected_value_after_useful_life = 10000, + depreciation_start_date = "2020-12-31" + ) + + expected_values = [ + ['2020-12-31', 30000.0], + ['2021-12-31', 30000.0], + ['2022-12-31', 30000.0] + ] + + for i, schedule in enumerate(asset.schedules): + self.assertEqual(expected_values[i][0], schedule.schedule_date) + self.assertEqual(expected_values[i][1], schedule.depreciation_amount) + + def test_set_accumulated_depreciation(self): + """Tests if set_accumulated_depreciation() returns the right values.""" + + asset = create_asset( + item_code = "Macbook Pro", + calculate_depreciation = 1, + available_for_use_date = "2019-12-31", + depreciation_method = "Straight Line", + frequency_of_depreciation = 12, + total_number_of_depreciations = 3, + expected_value_after_useful_life = 10000, + depreciation_start_date = "2020-12-31" + ) + + expected_values = [30000.0, 60000.0, 90000.0] + + for i, schedule in enumerate(asset.schedules): + self.assertEqual(expected_values[i], schedule.accumulated_depreciation_amount) + + def test_check_is_pro_rata(self): + """Tests if check_is_pro_rata() returns the right value(i.e. checks if has_pro_rata is accurate).""" + + asset = create_asset( + item_code = "Macbook Pro", + available_for_use_date = "2019-12-31", + do_not_save = 1 + ) + + asset.calculate_depreciation = 1 + asset.append("finance_books", { + "depreciation_method": "Straight Line", + "frequency_of_depreciation": 12, + "total_number_of_depreciations": 3, + "expected_value_after_useful_life": 10000, + "depreciation_start_date": "2020-12-31" + }) + + has_pro_rata = asset.check_is_pro_rata(asset.finance_books[0]) + self.assertFalse(has_pro_rata) + + asset.finance_books = [] + asset.append("finance_books", { + "depreciation_method": "Straight Line", + "frequency_of_depreciation": 12, + "total_number_of_depreciations": 3, + "expected_value_after_useful_life": 10000, + "depreciation_start_date": "2020-07-01" + }) + + has_pro_rata = asset.check_is_pro_rata(asset.finance_books[0]) + self.assertTrue(has_pro_rata) + + def test_expected_value_after_useful_life_greater_than_purchase_amount(self): + """Tests if an error is raised when expected_value_after_useful_life(110,000) > gross_purchase_amount(100,000).""" + + asset = create_asset( + item_code = "Macbook Pro", + calculate_depreciation = 1, + available_for_use_date = "2019-12-31", + total_number_of_depreciations = 3, + expected_value_after_useful_life = 110000, + depreciation_start_date = "2020-07-01", + do_not_save = 1 + ) + + self.assertRaises(frappe.ValidationError, asset.save) + + def test_depreciation_start_date(self): + """Tests if an error is raised when neither depreciation_start_date nor available_for_use_date are specified.""" + + asset = create_asset( + item_code = "Macbook Pro", + calculate_depreciation = 1, + total_number_of_depreciations = 3, + expected_value_after_useful_life = 110000, + do_not_save = 1 + ) + + self.assertRaises(frappe.ValidationError, asset.save) + + def test_opening_accumulated_depreciation(self): + """Tests if an error is raised when opening_accumulated_depreciation > (gross_purchase_amount - expected_value_after_useful_life).""" + + asset = create_asset( + item_code = "Macbook Pro", + calculate_depreciation = 1, + available_for_use_date = "2019-12-31", + total_number_of_depreciations = 3, + expected_value_after_useful_life = 10000, + depreciation_start_date = "2020-07-01", + opening_accumulated_depreciation = 100000, + do_not_save = 1 + ) + + self.assertRaises(frappe.ValidationError, asset.save) + + def test_number_of_depreciations_booked(self): + """Tests if an error is raised when number_of_depreciations_booked is not specified when opening_accumulated_depreciation is.""" + + asset = create_asset( + item_code = "Macbook Pro", + calculate_depreciation = 1, + available_for_use_date = "2019-12-31", + total_number_of_depreciations = 3, + expected_value_after_useful_life = 10000, + depreciation_start_date = "2020-07-01", + opening_accumulated_depreciation = 10000, + do_not_save = 1 + ) + + self.assertRaises(frappe.ValidationError, asset.save) + + def test_number_of_depreciations(self): + """Tests if an error is raised when number_of_depreciations_booked > total_number_of_depreciations.""" + + asset = create_asset( + item_code = "Macbook Pro", + calculate_depreciation = 1, + available_for_use_date = "2019-12-31", + total_number_of_depreciations = 3, + expected_value_after_useful_life = 10000, + depreciation_start_date = "2020-07-01", + opening_accumulated_depreciation = 10000, + number_of_depreciations_booked = 5, + do_not_save = 1 + ) + + self.assertRaises(frappe.ValidationError, asset.save) + + def test_depreciation_start_date_is_before_purchase_date(self): + asset = create_asset( + item_code = "Macbook Pro", + calculate_depreciation = 1, + available_for_use_date = "2019-12-31", + total_number_of_depreciations = 3, + expected_value_after_useful_life = 10000, + depreciation_start_date = "2014-07-01", + do_not_save = 1 + ) + + self.assertRaises(frappe.ValidationError, asset.save) + + def test_depreciation_start_date_is_before_available_for_use_date(self): + asset = create_asset( + item_code = "Macbook Pro", + calculate_depreciation = 1, + available_for_use_date = "2019-12-31", + total_number_of_depreciations = 3, + expected_value_after_useful_life = 10000, + depreciation_start_date = "2018-07-01", + do_not_save = 1 + ) + + self.assertRaises(frappe.ValidationError, asset.save) + + def test_finance_books_are_present_if_calculate_depreciation_is_enabled(self): + asset = create_asset(item_code="Macbook Pro", do_not_save=1) + asset.calculate_depreciation = 1 + + self.assertRaises(frappe.ValidationError, asset.save) + + def test_post_depreciation_entries(self): + """Tests if post_depreciation_entries() works as expected.""" + + asset = create_asset( + item_code = "Macbook Pro", + calculate_depreciation = 1, + available_for_use_date = "2019-12-31", + depreciation_start_date = "2020-12-31", + frequency_of_depreciation = 12, + total_number_of_depreciations = 3, + expected_value_after_useful_life = 10000, + submit = 1 + ) + + post_depreciation_entries(date="2021-06-01") + asset.load_from_db() + + self.assertTrue(asset.schedules[0].journal_entry) + self.assertFalse(asset.schedules[1].journal_entry) + self.assertFalse(asset.schedules[2].journal_entry) + + def test_clear_depreciation_schedule(self): + """Tests if clear_depreciation_schedule() works as expected.""" + + asset = create_asset( + item_code = "Macbook Pro", + calculate_depreciation = 1, + available_for_use_date = "2019-12-31", + depreciation_start_date = "2020-12-31", + frequency_of_depreciation = 12, + total_number_of_depreciations = 3, + expected_value_after_useful_life = 10000, + submit = 1 + ) + + post_depreciation_entries(date="2021-06-01") + asset.load_from_db() + + asset.clear_depreciation_schedule() + + self.assertEqual(len(asset.schedules), 1) + + def test_depreciation_entry_cancellation(self): + asset = create_asset( + item_code = "Macbook Pro", + calculate_depreciation = 1, + purchase_date = "2020-06-06", + available_for_use_date = "2020-06-06", + depreciation_start_date = "2020-12-31", + frequency_of_depreciation = 10, + total_number_of_depreciations = 3, + expected_value_after_useful_life = 10000, + submit = 1 + ) + + post_depreciation_entries(date="2021-01-01") + + asset.load_from_db() + + # cancel depreciation entry + depr_entry = asset.get("schedules")[0].journal_entry + self.assertTrue(depr_entry) + frappe.get_doc("Journal Entry", depr_entry).cancel() + + asset.load_from_db() + depr_entry = asset.get("schedules")[0].journal_entry + self.assertFalse(depr_entry) + + def test_asset_expected_value_after_useful_life(self): + asset = create_asset( + item_code = "Macbook Pro", + calculate_depreciation = 1, + available_for_use_date = "2020-06-06", + purchase_date = "2020-06-06", + frequency_of_depreciation = 10, + total_number_of_depreciations = 3, + expected_value_after_useful_life = 10000 + ) + + accumulated_depreciation_after_full_schedule = \ + max(d.accumulated_depreciation_amount for d in asset.get("schedules")) + + asset_value_after_full_schedule = (flt(asset.gross_purchase_amount) - + flt(accumulated_depreciation_after_full_schedule)) + + self.assertTrue(asset.finance_books[0].expected_value_after_useful_life >= asset_value_after_full_schedule) + + def test_gle_made_by_depreciation_entries(self): + asset = create_asset( + item_code = "Macbook Pro", + calculate_depreciation = 1, + purchase_date = "2020-01-30", + available_for_use_date = "2020-01-30", + depreciation_start_date = "2020-12-31", + frequency_of_depreciation = 10, + total_number_of_depreciations = 3, + expected_value_after_useful_life = 10000, + submit = 1 + ) + + self.assertEqual(asset.status, "Submitted") + + frappe.db.set_value("Company", "_Test Company", "series_for_depreciation_entry", "DEPR-") + post_depreciation_entries(date="2021-01-01") + asset.load_from_db() + + # check depreciation entry series + self.assertEqual(asset.get("schedules")[0].journal_entry[:4], "DEPR") + + expected_gle = ( + ("_Test Accumulated Depreciations - _TC", 0.0, 30000.0), + ("_Test Depreciations - _TC", 30000.0, 0.0) + ) + + gle = frappe.db.sql("""select account, debit, credit from `tabGL Entry` + where against_voucher_type='Asset' and against_voucher = %s + order by account""", asset.name) + + self.assertEqual(gle, expected_gle) + self.assertEqual(asset.get("value_after_depreciation"), 0) + def test_expected_value_change(self): + """ + tests if changing `expected_value_after_useful_life` + affects `value_after_depreciation` + """ + + asset = create_asset(calculate_depreciation=1) + asset.opening_accumulated_depreciation = 2000 + asset.number_of_depreciations_booked = 1 + + asset.finance_books[0].expected_value_after_useful_life = 100 + asset.save() + asset.reload() + self.assertEquals(asset.finance_books[0].value_after_depreciation, 98000.0) + + # changing expected_value_after_useful_life shouldn't affect value_after_depreciation + asset.finance_books[0].expected_value_after_useful_life = 200 + asset.save() + asset.reload() + self.assertEquals(asset.finance_books[0].value_after_depreciation, 98000.0) + def create_asset_data(): if not frappe.db.exists("Asset Category", "Computers"): create_asset_category() @@ -697,32 +1010,37 @@ def create_asset(**args): asset = frappe.get_doc({ "doctype": "Asset", "asset_name": args.asset_name or "Macbook Pro 1", - "asset_category": "Computers", + "asset_category": args.asset_category or "Computers", "item_code": args.item_code or "Macbook Pro", - "company": args.company or"_Test Company", - "purchase_date": "2015-01-01", + "company": args.company or "_Test Company", + "purchase_date": args.purchase_date or "2015-01-01", "calculate_depreciation": args.calculate_depreciation or 0, - "gross_purchase_amount": 100000, - "purchase_receipt_amount": 100000, - "expected_value_after_useful_life": 10000, + "opening_accumulated_depreciation": args.opening_accumulated_depreciation or 0, + "number_of_depreciations_booked": args.number_of_depreciations_booked or 0, + "gross_purchase_amount": args.gross_purchase_amount or 100000, + "purchase_receipt_amount": args.purchase_receipt_amount or 100000, "warehouse": args.warehouse or "_Test Warehouse - _TC", - "available_for_use_date": "2020-06-06", - "location": "Test Location", - "asset_owner": "Company", - "is_existing_asset": 1 + "available_for_use_date": args.available_for_use_date or "2020-06-06", + "location": args.location or "Test Location", + "asset_owner": args.asset_owner or "Company", + "is_existing_asset": args.is_existing_asset or 1 }) if asset.calculate_depreciation: asset.append("finance_books", { - "depreciation_method": "Straight Line", - "frequency_of_depreciation": 12, - "total_number_of_depreciations": 5 + "finance_book": args.finance_book, + "depreciation_method": args.depreciation_method or "Straight Line", + "frequency_of_depreciation": args.frequency_of_depreciation or 12, + "total_number_of_depreciations": args.total_number_of_depreciations or 5, + "expected_value_after_useful_life": args.expected_value_after_useful_life or 0, + "depreciation_start_date": args.depreciation_start_date }) - try: - asset.save() - except frappe.DuplicateEntryError: - pass + if not args.do_not_save: + try: + asset.save() + except frappe.DuplicateEntryError: + pass if args.submit: asset.submit() @@ -773,3 +1091,6 @@ def set_depreciation_settings_in_company(): # Enable booking asset depreciation entry automatically frappe.db.set_value("Accounts Settings", None, "book_asset_depreciation_entry_automatically", 1) + +def enable_cwip_accounting(asset_category, enable=1): + frappe.db.set_value("Asset Category", asset_category, "enable_cwip_accounting", enable) diff --git a/erpnext/assets/doctype/asset_category/asset_category.py b/erpnext/assets/doctype/asset_category/asset_category.py index 1e56c010c46..e2f3ca318f6 100644 --- a/erpnext/assets/doctype/asset_category/asset_category.py +++ b/erpnext/assets/doctype/asset_category/asset_category.py @@ -1,8 +1,6 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and contributors # For license information, please see license.txt -from __future__ import unicode_literals import frappe from frappe import _ diff --git a/erpnext/assets/doctype/asset_category/test_asset_category.py b/erpnext/assets/doctype/asset_category/test_asset_category.py index 53ec4ed38ef..3d19fa39d1e 100644 --- a/erpnext/assets/doctype/asset_category/test_asset_category.py +++ b/erpnext/assets/doctype/asset_category/test_asset_category.py @@ -1,7 +1,5 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors # See license.txt -from __future__ import unicode_literals import unittest diff --git a/erpnext/assets/doctype/asset_category_account/asset_category_account.py b/erpnext/assets/doctype/asset_category_account/asset_category_account.py index 66280acb2e8..e06d2335678 100644 --- a/erpnext/assets/doctype/asset_category_account/asset_category_account.py +++ b/erpnext/assets/doctype/asset_category_account/asset_category_account.py @@ -1,8 +1,6 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and contributors # For license information, please see license.txt -from __future__ import unicode_literals from frappe.model.document import Document diff --git a/erpnext/assets/doctype/asset_finance_book/asset_finance_book.py b/erpnext/assets/doctype/asset_finance_book/asset_finance_book.py index c4f095305c5..292ca138fd9 100644 --- a/erpnext/assets/doctype/asset_finance_book/asset_finance_book.py +++ b/erpnext/assets/doctype/asset_finance_book/asset_finance_book.py @@ -1,8 +1,6 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2018, Frappe Technologies Pvt. Ltd. and contributors # For license information, please see license.txt -from __future__ import unicode_literals from frappe.model.document import Document diff --git a/erpnext/assets/doctype/asset_maintenance/asset_maintenance.py b/erpnext/assets/doctype/asset_maintenance/asset_maintenance.py index ec55fa4efcb..4fc4c4cb993 100644 --- a/erpnext/assets/doctype/asset_maintenance/asset_maintenance.py +++ b/erpnext/assets/doctype/asset_maintenance/asset_maintenance.py @@ -1,8 +1,6 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2017, Frappe Technologies Pvt. Ltd. and contributors # For license information, please see license.txt -from __future__ import unicode_literals import frappe from frappe import _, throw diff --git a/erpnext/assets/doctype/asset_maintenance/test_asset_maintenance.py b/erpnext/assets/doctype/asset_maintenance/test_asset_maintenance.py index 0f915086a9f..8acb61b9671 100644 --- a/erpnext/assets/doctype/asset_maintenance/test_asset_maintenance.py +++ b/erpnext/assets/doctype/asset_maintenance/test_asset_maintenance.py @@ -1,7 +1,5 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2017, Frappe Technologies Pvt. Ltd. and Contributors # See license.txt -from __future__ import unicode_literals import unittest diff --git a/erpnext/assets/doctype/asset_maintenance_log/asset_maintenance_log.py b/erpnext/assets/doctype/asset_maintenance_log/asset_maintenance_log.py index 1f2393649d0..7d3453fc982 100644 --- a/erpnext/assets/doctype/asset_maintenance_log/asset_maintenance_log.py +++ b/erpnext/assets/doctype/asset_maintenance_log/asset_maintenance_log.py @@ -1,8 +1,6 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2017, Frappe Technologies Pvt. Ltd. and contributors # For license information, please see license.txt -from __future__ import unicode_literals import frappe from frappe import _ diff --git a/erpnext/assets/doctype/asset_maintenance_log/test_asset_maintenance_log.py b/erpnext/assets/doctype/asset_maintenance_log/test_asset_maintenance_log.py index 7ad69e92aba..9980ff31f62 100644 --- a/erpnext/assets/doctype/asset_maintenance_log/test_asset_maintenance_log.py +++ b/erpnext/assets/doctype/asset_maintenance_log/test_asset_maintenance_log.py @@ -1,7 +1,5 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2017, Frappe Technologies Pvt. Ltd. and Contributors # See license.txt -from __future__ import unicode_literals import unittest diff --git a/erpnext/assets/doctype/asset_maintenance_task/asset_maintenance_task.py b/erpnext/assets/doctype/asset_maintenance_task/asset_maintenance_task.py index 2280f557284..1078208b2fc 100644 --- a/erpnext/assets/doctype/asset_maintenance_task/asset_maintenance_task.py +++ b/erpnext/assets/doctype/asset_maintenance_task/asset_maintenance_task.py @@ -1,8 +1,6 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2017, Frappe Technologies Pvt. Ltd. and contributors # For license information, please see license.txt -from __future__ import unicode_literals from frappe.model.document import Document diff --git a/erpnext/assets/doctype/asset_maintenance_team/asset_maintenance_team.py b/erpnext/assets/doctype/asset_maintenance_team/asset_maintenance_team.py index 46e9029941c..938c99b4f6b 100644 --- a/erpnext/assets/doctype/asset_maintenance_team/asset_maintenance_team.py +++ b/erpnext/assets/doctype/asset_maintenance_team/asset_maintenance_team.py @@ -1,8 +1,6 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2017, Frappe Technologies Pvt. Ltd. and contributors # For license information, please see license.txt -from __future__ import unicode_literals from frappe.model.document import Document diff --git a/erpnext/assets/doctype/asset_maintenance_team/test_asset_maintenance_team.py b/erpnext/assets/doctype/asset_maintenance_team/test_asset_maintenance_team.py index 8d757b74c06..732ab4ae484 100644 --- a/erpnext/assets/doctype/asset_maintenance_team/test_asset_maintenance_team.py +++ b/erpnext/assets/doctype/asset_maintenance_team/test_asset_maintenance_team.py @@ -1,7 +1,5 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2017, Frappe Technologies Pvt. Ltd. and Contributors # See license.txt -from __future__ import unicode_literals import unittest diff --git a/erpnext/assets/doctype/asset_movement/asset_movement.py b/erpnext/assets/doctype/asset_movement/asset_movement.py index 901bdb5c001..07bea616da6 100644 --- a/erpnext/assets/doctype/asset_movement/asset_movement.py +++ b/erpnext/assets/doctype/asset_movement/asset_movement.py @@ -1,8 +1,6 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and contributors # For license information, please see license.txt -from __future__ import unicode_literals import frappe from frappe import _ diff --git a/erpnext/assets/doctype/asset_movement/test_asset_movement.py b/erpnext/assets/doctype/asset_movement/test_asset_movement.py index 058bbd1abd6..025facc4fda 100644 --- a/erpnext/assets/doctype/asset_movement/test_asset_movement.py +++ b/erpnext/assets/doctype/asset_movement/test_asset_movement.py @@ -1,7 +1,5 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors # See license.txt -from __future__ import unicode_literals import unittest diff --git a/erpnext/assets/doctype/asset_movement_item/asset_movement_item.py b/erpnext/assets/doctype/asset_movement_item/asset_movement_item.py index 24da37176e8..e25226d580d 100644 --- a/erpnext/assets/doctype/asset_movement_item/asset_movement_item.py +++ b/erpnext/assets/doctype/asset_movement_item/asset_movement_item.py @@ -1,8 +1,6 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2019, Frappe Technologies Pvt. Ltd. and contributors # For license information, please see license.txt -from __future__ import unicode_literals # import frappe from frappe.model.document import Document diff --git a/erpnext/assets/doctype/asset_repair/asset_repair.py b/erpnext/assets/doctype/asset_repair/asset_repair.py index 99a7d9bfbf8..d780c18ad02 100644 --- a/erpnext/assets/doctype/asset_repair/asset_repair.py +++ b/erpnext/assets/doctype/asset_repair/asset_repair.py @@ -1,8 +1,6 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2017, Frappe Technologies Pvt. Ltd. and contributors # For license information, please see license.txt -from __future__ import unicode_literals import frappe from frappe import _ diff --git a/erpnext/assets/doctype/asset_repair/test_asset_repair.py b/erpnext/assets/doctype/asset_repair/test_asset_repair.py index 9945a328cfc..81b4f6c4499 100644 --- a/erpnext/assets/doctype/asset_repair/test_asset_repair.py +++ b/erpnext/assets/doctype/asset_repair/test_asset_repair.py @@ -1,7 +1,5 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2017, Frappe Technologies Pvt. Ltd. and Contributors # See license.txt -from __future__ import unicode_literals import unittest @@ -22,7 +20,7 @@ class TestAssetRepair(unittest.TestCase): frappe.db.sql("delete from `tabTax Rule`") def test_update_status(self): - asset = create_asset() + asset = create_asset(submit=1) initial_status = asset.status asset_repair = create_asset_repair(asset = asset) @@ -76,7 +74,7 @@ class TestAssetRepair(unittest.TestCase): self.assertEqual(stock_entry.items[0].qty, asset_repair.stock_items[0].consumed_quantity) def test_increase_in_asset_value_due_to_stock_consumption(self): - asset = create_asset(calculate_depreciation = 1) + asset = create_asset(calculate_depreciation = 1, submit=1) initial_asset_value = get_asset_value(asset) asset_repair = create_asset_repair(asset= asset, stock_consumption = 1, submit = 1) asset.reload() @@ -85,7 +83,7 @@ class TestAssetRepair(unittest.TestCase): self.assertEqual(asset_repair.stock_items[0].total_value, increase_in_asset_value) def test_increase_in_asset_value_due_to_repair_cost_capitalisation(self): - asset = create_asset(calculate_depreciation = 1) + asset = create_asset(calculate_depreciation = 1, submit=1) initial_asset_value = get_asset_value(asset) asset_repair = create_asset_repair(asset= asset, capitalize_repair_cost = 1, submit = 1) asset.reload() @@ -103,7 +101,7 @@ class TestAssetRepair(unittest.TestCase): self.assertEqual(asset_repair.name, gl_entry.voucher_no) def test_increase_in_asset_life(self): - asset = create_asset(calculate_depreciation = 1) + asset = create_asset(calculate_depreciation = 1, submit=1) initial_num_of_depreciations = num_of_depreciations(asset) create_asset_repair(asset= asset, capitalize_repair_cost = 1, submit = 1) asset.reload() @@ -126,7 +124,7 @@ def create_asset_repair(**args): if args.asset: asset = args.asset else: - asset = create_asset(is_existing_asset = 1) + asset = create_asset(is_existing_asset = 1, submit=1) asset_repair = frappe.new_doc("Asset Repair") asset_repair.update({ "asset": asset.name, diff --git a/erpnext/assets/doctype/asset_value_adjustment/asset_value_adjustment.js b/erpnext/assets/doctype/asset_value_adjustment/asset_value_adjustment.js index 79c8861bcdc..36f510b18ee 100644 --- a/erpnext/assets/doctype/asset_value_adjustment/asset_value_adjustment.js +++ b/erpnext/assets/doctype/asset_value_adjustment/asset_value_adjustment.js @@ -14,6 +14,14 @@ frappe.ui.form.on('Asset Value Adjustment', { } } }); + frm.set_query('asset', function() { + return { + filters: { + calculate_depreciation: 1, + docstatus: 1 + } + }; + }); }, onload: function(frm) { diff --git a/erpnext/assets/doctype/asset_value_adjustment/asset_value_adjustment.py b/erpnext/assets/doctype/asset_value_adjustment/asset_value_adjustment.py index 2c11018caa9..0b646ed4ede 100644 --- a/erpnext/assets/doctype/asset_value_adjustment/asset_value_adjustment.py +++ b/erpnext/assets/doctype/asset_value_adjustment/asset_value_adjustment.py @@ -1,8 +1,6 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2018, Frappe Technologies Pvt. Ltd. and contributors # For license information, please see license.txt -from __future__ import unicode_literals import frappe from frappe import _ @@ -12,7 +10,11 @@ from frappe.utils import cint, date_diff, flt, formatdate, getdate from erpnext.accounts.doctype.accounting_dimension.accounting_dimension import ( get_checks_for_pl_and_bs_accounts, ) +from erpnext.assets.doctype.asset.asset import get_depreciation_amount from erpnext.assets.doctype.asset.depreciation import get_depreciation_accounts +from erpnext.regional.india.utils import ( + get_depreciation_amount as get_depreciation_amount_for_india, +) class AssetValueAdjustment(Document): @@ -92,6 +94,7 @@ class AssetValueAdjustment(Document): def reschedule_depreciations(self, asset_value): asset = frappe.get_doc('Asset', self.asset) + country = frappe.get_value('Company', self.company, 'country') for d in asset.finance_books: d.value_after_depreciation = asset_value @@ -113,8 +116,10 @@ class AssetValueAdjustment(Document): depreciation_amount = days * rate_per_day from_date = data.schedule_date else: - depreciation_amount = asset.get_depreciation_amount(value_after_depreciation, - no_of_depreciations, d) + if country == "India": + depreciation_amount = get_depreciation_amount_for_india(asset, value_after_depreciation, d) + else: + depreciation_amount = get_depreciation_amount(asset, value_after_depreciation, d) if depreciation_amount: value_after_depreciation -= flt(depreciation_amount) diff --git a/erpnext/assets/doctype/asset_value_adjustment/test_asset_value_adjustment.py b/erpnext/assets/doctype/asset_value_adjustment/test_asset_value_adjustment.py index 52728d6fd69..ef13c5617f5 100644 --- a/erpnext/assets/doctype/asset_value_adjustment/test_asset_value_adjustment.py +++ b/erpnext/assets/doctype/asset_value_adjustment/test_asset_value_adjustment.py @@ -1,7 +1,5 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2018, Frappe Technologies Pvt. Ltd. and Contributors # See license.txt -from __future__ import unicode_literals import unittest diff --git a/erpnext/assets/doctype/depreciation_schedule/depreciation_schedule.py b/erpnext/assets/doctype/depreciation_schedule/depreciation_schedule.py index 3199b7dc8dc..b597c587522 100644 --- a/erpnext/assets/doctype/depreciation_schedule/depreciation_schedule.py +++ b/erpnext/assets/doctype/depreciation_schedule/depreciation_schedule.py @@ -1,8 +1,6 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2017, Frappe Technologies Pvt. Ltd. and contributors # For license information, please see license.txt -from __future__ import unicode_literals from frappe.model.document import Document diff --git a/erpnext/assets/doctype/linked_location/linked_location.py b/erpnext/assets/doctype/linked_location/linked_location.py index e622e84dc32..e1257f3db16 100644 --- a/erpnext/assets/doctype/linked_location/linked_location.py +++ b/erpnext/assets/doctype/linked_location/linked_location.py @@ -1,8 +1,6 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2018, Frappe Technologies Pvt. Ltd. and contributors # For license information, please see license.txt -from __future__ import unicode_literals from frappe.model.document import Document diff --git a/erpnext/assets/doctype/location/location.py b/erpnext/assets/doctype/location/location.py index 1430306bec1..abc7325cf6c 100644 --- a/erpnext/assets/doctype/location/location.py +++ b/erpnext/assets/doctype/location/location.py @@ -1,8 +1,6 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2018, Frappe Technologies Pvt. Ltd. and contributors # For license information, please see license.txt -from __future__ import unicode_literals import json import math diff --git a/erpnext/assets/doctype/location/test_location.py b/erpnext/assets/doctype/location/test_location.py index c98b0b0936c..36e1dd4ce4b 100644 --- a/erpnext/assets/doctype/location/test_location.py +++ b/erpnext/assets/doctype/location/test_location.py @@ -1,7 +1,5 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2018, Frappe Technologies Pvt. Ltd. and Contributors # See license.txt -from __future__ import unicode_literals import json import unittest diff --git a/erpnext/assets/doctype/maintenance_team_member/maintenance_team_member.py b/erpnext/assets/doctype/maintenance_team_member/maintenance_team_member.py index 8fc5c9c43c1..c3ede94bc68 100644 --- a/erpnext/assets/doctype/maintenance_team_member/maintenance_team_member.py +++ b/erpnext/assets/doctype/maintenance_team_member/maintenance_team_member.py @@ -1,8 +1,6 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2017, Frappe Technologies Pvt. Ltd. and contributors # For license information, please see license.txt -from __future__ import unicode_literals from frappe.model.document import Document diff --git a/erpnext/assets/doctype/maintenance_team_member/test_maintenance_team_member.py b/erpnext/assets/doctype/maintenance_team_member/test_maintenance_team_member.py index f8958c6bbef..911a6544e9a 100644 --- a/erpnext/assets/doctype/maintenance_team_member/test_maintenance_team_member.py +++ b/erpnext/assets/doctype/maintenance_team_member/test_maintenance_team_member.py @@ -1,7 +1,5 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2017, Frappe Technologies Pvt. Ltd. and Contributors # See license.txt -from __future__ import unicode_literals import unittest diff --git a/erpnext/assets/report/fixed_asset_register/fixed_asset_register.js b/erpnext/assets/report/fixed_asset_register/fixed_asset_register.js index 75f42a9f783..06989a95da7 100644 --- a/erpnext/assets/report/fixed_asset_register/fixed_asset_register.js +++ b/erpnext/assets/report/fixed_asset_register/fixed_asset_register.js @@ -16,9 +16,8 @@ frappe.query_reports["Fixed Asset Register"] = { fieldname:"status", label: __("Status"), fieldtype: "Select", - options: "In Location\nDisposed", - default: 'In Location', - reqd: 1 + options: "\nIn Location\nDisposed", + default: 'In Location' }, { "fieldname":"filter_based_on", diff --git a/erpnext/assets/report/fixed_asset_register/fixed_asset_register.py b/erpnext/assets/report/fixed_asset_register/fixed_asset_register.py index e370b9d0cb3..db513364f49 100644 --- a/erpnext/assets/report/fixed_asset_register/fixed_asset_register.py +++ b/erpnext/assets/report/fixed_asset_register/fixed_asset_register.py @@ -1,7 +1,6 @@ # Copyright (c) 2013, Frappe Technologies Pvt. Ltd. and contributors # For license information, please see license.txt -from __future__ import unicode_literals import frappe from frappe import _ @@ -45,12 +44,13 @@ def get_conditions(filters): if filters.get('cost_center'): conditions["cost_center"] = filters.get('cost_center') - # In Store assets are those that are not sold or scrapped - operand = 'not in' - if status not in 'In Location': - operand = 'in' + if status: + # In Store assets are those that are not sold or scrapped + operand = 'not in' + if status not in 'In Location': + operand = 'in' - conditions['status'] = (operand, ['Sold', 'Scrapped']) + conditions['status'] = (operand, ['Sold', 'Scrapped']) return conditions diff --git a/erpnext/assets/workspace/assets/assets.json b/erpnext/assets/workspace/assets/assets.json index dfbf1a378e5..495de46e414 100644 --- a/erpnext/assets/workspace/assets/assets.json +++ b/erpnext/assets/workspace/assets/assets.json @@ -1,5 +1,4 @@ { - "category": "", "charts": [ { "chart_name": "Asset Value Analytics", @@ -8,18 +7,12 @@ ], "content": "[{\"type\": \"onboarding\", \"data\": {\"onboarding_name\":\"Assets\", \"col\": 12}}, {\"type\": \"chart\", \"data\": {\"chart_name\": \"Asset Value Analytics\", \"col\": 12}}, {\"type\": \"spacer\", \"data\": {\"col\": 12}}, {\"type\": \"header\", \"data\": {\"text\": \"Your Shortcuts\", \"level\": 4, \"col\": 12}}, {\"type\": \"shortcut\", \"data\": {\"shortcut_name\": \"Asset\", \"col\": 4}}, {\"type\": \"shortcut\", \"data\": {\"shortcut_name\": \"Asset Category\", \"col\": 4}}, {\"type\": \"shortcut\", \"data\": {\"shortcut_name\": \"Fixed Asset Register\", \"col\": 4}}, {\"type\": \"shortcut\", \"data\": {\"shortcut_name\": \"Dashboard\", \"col\": 4}}, {\"type\": \"spacer\", \"data\": {\"col\": 12}}, {\"type\": \"header\", \"data\": {\"text\": \"Reports & Masters\", \"level\": 4, \"col\": 12}}, {\"type\": \"card\", \"data\": {\"card_name\": \"Assets\", \"col\": 4}}, {\"type\": \"card\", \"data\": {\"card_name\": \"Maintenance\", \"col\": 4}}, {\"type\": \"card\", \"data\": {\"card_name\": \"Reports\", \"col\": 4}}]", "creation": "2020-03-02 15:43:27.634865", - "developer_mode_only": 0, - "disable_user_customization": 0, "docstatus": 0, "doctype": "Workspace", - "extends": "", - "extends_another_page": 0, "for_user": "", "hide_custom": 0, "icon": "assets", "idx": 0, - "is_default": 0, - "is_standard": 0, "label": "Assets", "links": [ { @@ -179,15 +172,12 @@ "type": "Link" } ], - "modified": "2021-08-05 12:15:54.839452", + "modified": "2021-08-05 12:15:54.839453", "modified_by": "Administrator", "module": "Assets", "name": "Assets", - "onboarding": "Assets", "owner": "Administrator", "parent_page": "", - "pin_to_bottom": 0, - "pin_to_top": 0, "public": 1, "restrict_to_domain": "", "roles": [], diff --git a/erpnext/buying/__init__.py b/erpnext/buying/__init__.py index baffc488252..e69de29bb2d 100644 --- a/erpnext/buying/__init__.py +++ b/erpnext/buying/__init__.py @@ -1 +0,0 @@ -from __future__ import unicode_literals diff --git a/erpnext/buying/doctype/__init__.py b/erpnext/buying/doctype/__init__.py index baffc488252..e69de29bb2d 100644 --- a/erpnext/buying/doctype/__init__.py +++ b/erpnext/buying/doctype/__init__.py @@ -1 +0,0 @@ -from __future__ import unicode_literals diff --git a/erpnext/buying/doctype/buying_settings/buying_settings.js b/erpnext/buying/doctype/buying_settings/buying_settings.js index 944bb61cfeb..32431fc3910 100644 --- a/erpnext/buying/doctype/buying_settings/buying_settings.js +++ b/erpnext/buying/doctype/buying_settings/buying_settings.js @@ -11,7 +11,7 @@ frappe.tour['Buying Settings'] = [ { fieldname: "supp_master_name", title: "Supplier Naming By", - description: __("By default, the Supplier Name is set as per the Supplier Name entered. If you want Suppliers to be named by a ") + "Naming Series" + __(" choose the 'Naming Series' option."), + description: __("By default, the Supplier Name is set as per the Supplier Name entered. If you want Suppliers to be named by a Naming Series choose the 'Naming Series' option."), }, { fieldname: "buying_price_list", diff --git a/erpnext/buying/doctype/buying_settings/buying_settings.json b/erpnext/buying/doctype/buying_settings/buying_settings.json index b9c77d59b18..b828a43d3cf 100644 --- a/erpnext/buying/doctype/buying_settings/buying_settings.json +++ b/erpnext/buying/doctype/buying_settings/buying_settings.json @@ -28,7 +28,7 @@ "fieldname": "supp_master_name", "fieldtype": "Select", "label": "Supplier Naming By", - "options": "Supplier Name\nNaming Series" + "options": "Supplier Name\nNaming Series\nAuto Name" }, { "fieldname": "supplier_group", @@ -123,7 +123,7 @@ "index_web_pages_for_search": 1, "issingle": 1, "links": [], - "modified": "2021-06-24 10:38:28.934525", + "modified": "2021-09-08 19:26:23.548837", "modified_by": "Administrator", "module": "Buying", "name": "Buying Settings", diff --git a/erpnext/buying/doctype/buying_settings/buying_settings.py b/erpnext/buying/doctype/buying_settings/buying_settings.py index 9e72c1890c5..2b6ff43530f 100644 --- a/erpnext/buying/doctype/buying_settings/buying_settings.py +++ b/erpnext/buying/doctype/buying_settings/buying_settings.py @@ -3,7 +3,6 @@ # For license information, please see license.txt -from __future__ import unicode_literals import frappe from frappe.model.document import Document diff --git a/erpnext/buying/doctype/buying_settings/test_buying_settings.py b/erpnext/buying/doctype/buying_settings/test_buying_settings.py index 4998aebd6bb..cdb691de0c3 100644 --- a/erpnext/buying/doctype/buying_settings/test_buying_settings.py +++ b/erpnext/buying/doctype/buying_settings/test_buying_settings.py @@ -1,7 +1,5 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2019, Frappe Technologies Pvt. Ltd. and Contributors # See license.txt -from __future__ import unicode_literals # import frappe import unittest diff --git a/erpnext/buying/doctype/purchase_order/__init__.py b/erpnext/buying/doctype/purchase_order/__init__.py index baffc488252..e69de29bb2d 100644 --- a/erpnext/buying/doctype/purchase_order/__init__.py +++ b/erpnext/buying/doctype/purchase_order/__init__.py @@ -1 +0,0 @@ -from __future__ import unicode_literals diff --git a/erpnext/buying/doctype/purchase_order/purchase_order.js b/erpnext/buying/doctype/purchase_order/purchase_order.js index 521432d296b..2005dac37d7 100644 --- a/erpnext/buying/doctype/purchase_order/purchase_order.js +++ b/erpnext/buying/doctype/purchase_order/purchase_order.js @@ -425,7 +425,10 @@ erpnext.buying.PurchaseOrderController = class PurchaseOrderController extends e status: ["!=", "Stopped"], per_ordered: ["<", 100], company: me.frm.doc.company - } + }, + allow_child_item_selection: true, + child_fielname: "items", + child_columns: ["item_code", "qty"] }) }, __("Get Items From")); diff --git a/erpnext/buying/doctype/purchase_order/purchase_order.json b/erpnext/buying/doctype/purchase_order/purchase_order.json index ef54538fcd4..896208f25e1 100644 --- a/erpnext/buying/doctype/purchase_order/purchase_order.json +++ b/erpnext/buying/doctype/purchase_order/purchase_order.json @@ -1121,6 +1121,7 @@ "fetch_from": "supplier.represents_company", "fieldname": "represents_company", "fieldtype": "Link", + "ignore_user_permissions": 1, "label": "Represents Company", "options": "Company", "read_only": 1 @@ -1143,7 +1144,7 @@ "idx": 105, "is_submittable": 1, "links": [], - "modified": "2021-08-30 20:03:14.008804", + "modified": "2021-09-28 13:10:47.955401", "modified_by": "Administrator", "module": "Buying", "name": "Purchase Order", diff --git a/erpnext/buying/doctype/purchase_order/purchase_order.py b/erpnext/buying/doctype/purchase_order/purchase_order.py index ac86337b257..5eab21bd9d3 100644 --- a/erpnext/buying/doctype/purchase_order/purchase_order.py +++ b/erpnext/buying/doctype/purchase_order/purchase_order.py @@ -1,7 +1,6 @@ # Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors # License: GNU General Public License v3. See license.txt -from __future__ import unicode_literals import json diff --git a/erpnext/buying/doctype/purchase_order/purchase_order_dashboard.py b/erpnext/buying/doctype/purchase_order/purchase_order_dashboard.py index af1dceb4070..0163595b51c 100644 --- a/erpnext/buying/doctype/purchase_order/purchase_order_dashboard.py +++ b/erpnext/buying/doctype/purchase_order/purchase_order_dashboard.py @@ -1,5 +1,3 @@ -from __future__ import unicode_literals - from frappe import _ diff --git a/erpnext/buying/doctype/purchase_order/test_purchase_order.py b/erpnext/buying/doctype/purchase_order/test_purchase_order.py index 1453b8e7e4d..9a63afc1303 100644 --- a/erpnext/buying/doctype/purchase_order/test_purchase_order.py +++ b/erpnext/buying/doctype/purchase_order/test_purchase_order.py @@ -1,7 +1,6 @@ # Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors # License: GNU General Public License v3. See license.txt -from __future__ import unicode_literals import json import unittest diff --git a/erpnext/buying/doctype/purchase_order_item/__init__.py b/erpnext/buying/doctype/purchase_order_item/__init__.py index baffc488252..e69de29bb2d 100644 --- a/erpnext/buying/doctype/purchase_order_item/__init__.py +++ b/erpnext/buying/doctype/purchase_order_item/__init__.py @@ -1 +0,0 @@ -from __future__ import unicode_literals diff --git a/erpnext/buying/doctype/purchase_order_item/purchase_order_item.py b/erpnext/buying/doctype/purchase_order_item/purchase_order_item.py index a391a3d0688..0cef0deee55 100644 --- a/erpnext/buying/doctype/purchase_order_item/purchase_order_item.py +++ b/erpnext/buying/doctype/purchase_order_item/purchase_order_item.py @@ -1,7 +1,6 @@ # Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors # License: GNU General Public License v3. See license.txt -from __future__ import unicode_literals import frappe from frappe.model.document import Document diff --git a/erpnext/buying/doctype/purchase_order_item_supplied/__init__.py b/erpnext/buying/doctype/purchase_order_item_supplied/__init__.py index baffc488252..e69de29bb2d 100644 --- a/erpnext/buying/doctype/purchase_order_item_supplied/__init__.py +++ b/erpnext/buying/doctype/purchase_order_item_supplied/__init__.py @@ -1 +0,0 @@ -from __future__ import unicode_literals diff --git a/erpnext/buying/doctype/purchase_order_item_supplied/purchase_order_item_supplied.py b/erpnext/buying/doctype/purchase_order_item_supplied/purchase_order_item_supplied.py index 909faeca6ad..c69b5ed7a4c 100644 --- a/erpnext/buying/doctype/purchase_order_item_supplied/purchase_order_item_supplied.py +++ b/erpnext/buying/doctype/purchase_order_item_supplied/purchase_order_item_supplied.py @@ -1,7 +1,6 @@ # Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors # License: GNU General Public License v3. See license.txt -from __future__ import unicode_literals from frappe.model.document import Document diff --git a/erpnext/buying/doctype/purchase_receipt_item_supplied/__init__.py b/erpnext/buying/doctype/purchase_receipt_item_supplied/__init__.py index baffc488252..e69de29bb2d 100644 --- a/erpnext/buying/doctype/purchase_receipt_item_supplied/__init__.py +++ b/erpnext/buying/doctype/purchase_receipt_item_supplied/__init__.py @@ -1 +0,0 @@ -from __future__ import unicode_literals diff --git a/erpnext/buying/doctype/purchase_receipt_item_supplied/purchase_receipt_item_supplied.py b/erpnext/buying/doctype/purchase_receipt_item_supplied/purchase_receipt_item_supplied.py index caec4e8b7aa..7b67921232a 100644 --- a/erpnext/buying/doctype/purchase_receipt_item_supplied/purchase_receipt_item_supplied.py +++ b/erpnext/buying/doctype/purchase_receipt_item_supplied/purchase_receipt_item_supplied.py @@ -1,7 +1,6 @@ # Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors # License: GNU General Public License v3. See license.txt -from __future__ import unicode_literals from frappe.model.document import Document diff --git a/erpnext/buying/doctype/request_for_quotation/request_for_quotation.py b/erpnext/buying/doctype/request_for_quotation/request_for_quotation.py index af1a9a907a9..2db750e75c4 100644 --- a/erpnext/buying/doctype/request_for_quotation/request_for_quotation.py +++ b/erpnext/buying/doctype/request_for_quotation/request_for_quotation.py @@ -1,8 +1,6 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and contributors # For license information, please see license.txt -from __future__ import unicode_literals import json @@ -14,7 +12,6 @@ from frappe.model.mapper import get_mapped_doc from frappe.utils import get_url from frappe.utils.print_format import download_pdf from frappe.utils.user import get_user_fullname -from six import string_types from erpnext.accounts.party import get_party_account_currency, get_party_details from erpnext.buying.utils import validate_for_items @@ -290,7 +287,7 @@ def make_supplier_quotation_from_rfq(source_name, target_doc=None, for_supplier= # This method is used to make supplier quotation from supplier's portal. @frappe.whitelist() def create_supplier_quotation(doc): - if isinstance(doc, string_types): + if isinstance(doc, str): doc = json.loads(doc) try: @@ -394,12 +391,10 @@ def get_item_from_material_requests_based_on_supplier(source_name, target_doc = @frappe.whitelist() def get_supplier_tag(): - if not frappe.cache().hget("Supplier", "Tags"): - filters = {"document_type": "Supplier"} - tags = list(set(tag.tag for tag in frappe.get_all("Tag Link", filters=filters, fields=["tag"]) if tag)) - frappe.cache().hset("Supplier", "Tags", tags) + filters = {"document_type": "Supplier"} + tags = list(set(tag.tag for tag in frappe.get_all("Tag Link", filters=filters, fields=["tag"]) if tag)) - return frappe.cache().hget("Supplier", "Tags") + return tags @frappe.whitelist() @frappe.validate_and_sanitize_search_inputs diff --git a/erpnext/buying/doctype/request_for_quotation/request_for_quotation_dashboard.py b/erpnext/buying/doctype/request_for_quotation/request_for_quotation_dashboard.py index 0708cab30a1..dc1cda126aa 100644 --- a/erpnext/buying/doctype/request_for_quotation/request_for_quotation_dashboard.py +++ b/erpnext/buying/doctype/request_for_quotation/request_for_quotation_dashboard.py @@ -1,6 +1,3 @@ -from __future__ import unicode_literals - - def get_data(): return { 'docstatus': 1, diff --git a/erpnext/buying/doctype/request_for_quotation/test_request_for_quotation.py b/erpnext/buying/doctype/request_for_quotation/test_request_for_quotation.py index 33fde8e6dc8..51901991b5a 100644 --- a/erpnext/buying/doctype/request_for_quotation/test_request_for_quotation.py +++ b/erpnext/buying/doctype/request_for_quotation/test_request_for_quotation.py @@ -1,7 +1,5 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors # See license.txt -from __future__ import unicode_literals import unittest diff --git a/erpnext/buying/doctype/request_for_quotation_item/request_for_quotation_item.py b/erpnext/buying/doctype/request_for_quotation_item/request_for_quotation_item.py index 35f3305b8ef..096aedee32a 100644 --- a/erpnext/buying/doctype/request_for_quotation_item/request_for_quotation_item.py +++ b/erpnext/buying/doctype/request_for_quotation_item/request_for_quotation_item.py @@ -1,8 +1,6 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and contributors # For license information, please see license.txt -from __future__ import unicode_literals from frappe.model.document import Document diff --git a/erpnext/buying/doctype/request_for_quotation_supplier/request_for_quotation_supplier.py b/erpnext/buying/doctype/request_for_quotation_supplier/request_for_quotation_supplier.py index 47c0deb39f3..dbaad478a3c 100644 --- a/erpnext/buying/doctype/request_for_quotation_supplier/request_for_quotation_supplier.py +++ b/erpnext/buying/doctype/request_for_quotation_supplier/request_for_quotation_supplier.py @@ -1,8 +1,6 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and contributors # For license information, please see license.txt -from __future__ import unicode_literals from frappe.model.document import Document diff --git a/erpnext/buying/doctype/supplier/__init__.py b/erpnext/buying/doctype/supplier/__init__.py index baffc488252..e69de29bb2d 100644 --- a/erpnext/buying/doctype/supplier/__init__.py +++ b/erpnext/buying/doctype/supplier/__init__.py @@ -1 +0,0 @@ -from __future__ import unicode_literals diff --git a/erpnext/buying/doctype/supplier/supplier.js b/erpnext/buying/doctype/supplier/supplier.js index 7ee91961ca5..f0899b06b57 100644 --- a/erpnext/buying/doctype/supplier/supplier.js +++ b/erpnext/buying/doctype/supplier/supplier.js @@ -83,6 +83,12 @@ frappe.ui.form.on("Supplier", { frm.trigger("get_supplier_group_details"); }, __('Actions')); + if (cint(frappe.defaults.get_default("enable_common_party_accounting"))) { + frm.add_custom_button(__('Link with Customer'), function () { + frm.trigger('show_party_link_dialog'); + }, __('Actions')); + } + // indicators erpnext.utils.set_party_dashboard_indicators(frm); } @@ -128,5 +134,42 @@ frappe.ui.form.on("Supplier", { else { frm.toggle_reqd("represents_company", false); } + }, + show_party_link_dialog: function(frm) { + const dialog = new frappe.ui.Dialog({ + title: __('Select a Customer'), + fields: [{ + fieldtype: 'Link', label: __('Customer'), + options: 'Customer', fieldname: 'customer', reqd: 1 + }], + primary_action: function({ customer }) { + frappe.call({ + method: 'erpnext.accounts.doctype.party_link.party_link.create_party_link', + args: { + primary_role: 'Supplier', + primary_party: frm.doc.name, + secondary_party: customer + }, + freeze: true, + callback: function() { + dialog.hide(); + frappe.msgprint({ + message: __('Successfully linked to Customer'), + alert: true + }); + }, + error: function() { + dialog.hide(); + frappe.msgprint({ + message: __('Linking to Customer Failed. Please try again.'), + title: __('Linking Failed'), + indicator: 'red' + }); + } + }); + }, + primary_action_label: __('Create Link') + }); + dialog.show(); } }); diff --git a/erpnext/buying/doctype/supplier/supplier.json b/erpnext/buying/doctype/supplier/supplier.json index c7a5db59941..a57d9a92bb3 100644 --- a/erpnext/buying/doctype/supplier/supplier.json +++ b/erpnext/buying/doctype/supplier/supplier.json @@ -25,7 +25,6 @@ "column_break0", "supplier_group", "supplier_type", - "pan", "allow_purchase_invoice_creation_without_purchase_order", "allow_purchase_invoice_creation_without_purchase_receipt", "disabled", @@ -176,11 +175,6 @@ "options": "Company\nIndividual", "reqd": 1 }, - { - "fieldname": "pan", - "fieldtype": "Data", - "label": "PAN" - }, { "fieldname": "language", "fieldtype": "Link", @@ -433,16 +427,17 @@ "image_field": "image", "links": [ { - "group": "Item Group", - "link_doctype": "Supplier Item Group", - "link_fieldname": "supplier" + "group": "Allowed Items", + "link_doctype": "Party Specific Item", + "link_fieldname": "party" } ], - "modified": "2021-08-27 18:02:44.314077", + "modified": "2021-10-20 22:03:33.147249", "modified_by": "Administrator", "module": "Buying", "name": "Supplier", "name_case": "Title Case", + "naming_rule": "By \"Naming Series\" field", "owner": "Administrator", "permissions": [ { diff --git a/erpnext/buying/doctype/supplier/supplier.py b/erpnext/buying/doctype/supplier/supplier.py index 2a9f784ec6e..32659d607b0 100644 --- a/erpnext/buying/doctype/supplier/supplier.py +++ b/erpnext/buying/doctype/supplier/supplier.py @@ -1,7 +1,6 @@ # Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors # License: GNU General Public License v3. See license.txt -from __future__ import unicode_literals import frappe import frappe.defaults @@ -10,7 +9,7 @@ from frappe.contacts.address_and_contact import ( delete_contact_and_address, load_address_and_contact, ) -from frappe.model.naming import set_name_by_naming_series +from frappe.model.naming import set_name_by_naming_series, set_name_from_naming_options from erpnext.accounts.party import get_dashboard_info, validate_party_accounts from erpnext.utilities.transaction_base import TransactionBase @@ -40,8 +39,10 @@ class Supplier(TransactionBase): supp_master_name = frappe.defaults.get_global_default('supp_master_name') if supp_master_name == 'Supplier Name': self.name = self.supplier_name - else: + elif supp_master_name == 'Naming Series': set_name_by_naming_series(self) + else: + self.name = set_name_from_naming_options(frappe.get_meta(self.doctype).autoname, self) def on_update(self): if not self.naming_series: diff --git a/erpnext/buying/doctype/supplier/supplier_dashboard.py b/erpnext/buying/doctype/supplier/supplier_dashboard.py index 16251035bd3..78efd8eea09 100644 --- a/erpnext/buying/doctype/supplier/supplier_dashboard.py +++ b/erpnext/buying/doctype/supplier/supplier_dashboard.py @@ -1,5 +1,3 @@ -from __future__ import unicode_literals - from frappe import _ diff --git a/erpnext/buying/doctype/supplier/test_supplier.py b/erpnext/buying/doctype/supplier/test_supplier.py index 8a4eefa4fd3..13fe9df13ee 100644 --- a/erpnext/buying/doctype/supplier/test_supplier.py +++ b/erpnext/buying/doctype/supplier/test_supplier.py @@ -1,6 +1,5 @@ # Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors # License: GNU General Public License v3. See license.txt -from __future__ import unicode_literals import unittest diff --git a/erpnext/buying/doctype/supplier_item_group/supplier_item_group.py b/erpnext/buying/doctype/supplier_item_group/supplier_item_group.py deleted file mode 100644 index 6d71f7d5160..00000000000 --- a/erpnext/buying/doctype/supplier_item_group/supplier_item_group.py +++ /dev/null @@ -1,20 +0,0 @@ -# -*- coding: utf-8 -*- -# Copyright (c) 2021, Frappe Technologies Pvt. Ltd. and contributors -# For license information, please see license.txt - -from __future__ import unicode_literals - -import frappe -from frappe import _ -from frappe.model.document import Document - - -class SupplierItemGroup(Document): - def validate(self): - exists = frappe.db.exists({ - 'doctype': 'Supplier Item Group', - 'supplier': self.supplier, - 'item_group': self.item_group - }) - if exists: - frappe.throw(_("Item Group has already been linked to this supplier.")) diff --git a/erpnext/buying/doctype/supplier_quotation/__init__.py b/erpnext/buying/doctype/supplier_quotation/__init__.py index baffc488252..e69de29bb2d 100644 --- a/erpnext/buying/doctype/supplier_quotation/__init__.py +++ b/erpnext/buying/doctype/supplier_quotation/__init__.py @@ -1 +0,0 @@ -from __future__ import unicode_literals diff --git a/erpnext/buying/doctype/supplier_quotation/supplier_quotation.py b/erpnext/buying/doctype/supplier_quotation/supplier_quotation.py index af462fc6859..d65ab94a6d3 100644 --- a/erpnext/buying/doctype/supplier_quotation/supplier_quotation.py +++ b/erpnext/buying/doctype/supplier_quotation/supplier_quotation.py @@ -1,7 +1,6 @@ # Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors # License: GNU General Public License v3. See license.txt -from __future__ import unicode_literals import frappe from frappe import _ diff --git a/erpnext/buying/doctype/supplier_quotation/supplier_quotation_dashboard.py b/erpnext/buying/doctype/supplier_quotation/supplier_quotation_dashboard.py index 014b1025dd3..236b91ad58b 100644 --- a/erpnext/buying/doctype/supplier_quotation/supplier_quotation_dashboard.py +++ b/erpnext/buying/doctype/supplier_quotation/supplier_quotation_dashboard.py @@ -1,5 +1,3 @@ -from __future__ import unicode_literals - from frappe import _ diff --git a/erpnext/buying/doctype/supplier_quotation/test_supplier_quotation.py b/erpnext/buying/doctype/supplier_quotation/test_supplier_quotation.py index 2db8e22f08b..d48ac7eb3b4 100644 --- a/erpnext/buying/doctype/supplier_quotation/test_supplier_quotation.py +++ b/erpnext/buying/doctype/supplier_quotation/test_supplier_quotation.py @@ -2,7 +2,6 @@ # License: GNU General Public License v3. See license.txt -from __future__ import unicode_literals import unittest diff --git a/erpnext/buying/doctype/supplier_quotation_item/__init__.py b/erpnext/buying/doctype/supplier_quotation_item/__init__.py index baffc488252..e69de29bb2d 100644 --- a/erpnext/buying/doctype/supplier_quotation_item/__init__.py +++ b/erpnext/buying/doctype/supplier_quotation_item/__init__.py @@ -1 +0,0 @@ -from __future__ import unicode_literals diff --git a/erpnext/buying/doctype/supplier_quotation_item/supplier_quotation_item.py b/erpnext/buying/doctype/supplier_quotation_item/supplier_quotation_item.py index 03adab54626..672de1ac284 100644 --- a/erpnext/buying/doctype/supplier_quotation_item/supplier_quotation_item.py +++ b/erpnext/buying/doctype/supplier_quotation_item/supplier_quotation_item.py @@ -1,7 +1,6 @@ # Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors # License: GNU General Public License v3. See license.txt -from __future__ import unicode_literals from frappe.model.document import Document diff --git a/erpnext/buying/doctype/supplier_scorecard/supplier_scorecard.py b/erpnext/buying/doctype/supplier_scorecard/supplier_scorecard.py index f944fe44665..3bcc0debae9 100644 --- a/erpnext/buying/doctype/supplier_scorecard/supplier_scorecard.py +++ b/erpnext/buying/doctype/supplier_scorecard/supplier_scorecard.py @@ -1,8 +1,6 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2017, Frappe Technologies Pvt. Ltd. and contributors # For license information, please see license.txt -from __future__ import unicode_literals import time from datetime import timedelta diff --git a/erpnext/buying/doctype/supplier_scorecard/supplier_scorecard_dashboard.py b/erpnext/buying/doctype/supplier_scorecard/supplier_scorecard_dashboard.py index 7186e01d084..5d693263f8c 100644 --- a/erpnext/buying/doctype/supplier_scorecard/supplier_scorecard_dashboard.py +++ b/erpnext/buying/doctype/supplier_scorecard/supplier_scorecard_dashboard.py @@ -1,5 +1,3 @@ -from __future__ import unicode_literals - from frappe import _ diff --git a/erpnext/buying/doctype/supplier_scorecard/test_supplier_scorecard.py b/erpnext/buying/doctype/supplier_scorecard/test_supplier_scorecard.py index ef7fae3f111..49e33517e6f 100644 --- a/erpnext/buying/doctype/supplier_scorecard/test_supplier_scorecard.py +++ b/erpnext/buying/doctype/supplier_scorecard/test_supplier_scorecard.py @@ -1,7 +1,5 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2017, Frappe Technologies Pvt. Ltd. and Contributors # See license.txt -from __future__ import unicode_literals import unittest diff --git a/erpnext/buying/doctype/supplier_scorecard_criteria/supplier_scorecard_criteria.json b/erpnext/buying/doctype/supplier_scorecard_criteria/supplier_scorecard_criteria.json index 2623585aeae..3668b2505f6 100644 --- a/erpnext/buying/doctype/supplier_scorecard_criteria/supplier_scorecard_criteria.json +++ b/erpnext/buying/doctype/supplier_scorecard_criteria/supplier_scorecard_criteria.json @@ -1,184 +1,70 @@ { - "allow_copy": 0, - "allow_guest_to_view": 0, - "allow_import": 0, - "allow_rename": 0, - "autoname": "field:criteria_name", - "beta": 0, - "creation": "2017-05-29 01:32:43.064891", - "custom": 0, - "docstatus": 0, - "doctype": "DocType", - "document_type": "", - "editable_grid": 1, - "engine": "InnoDB", + "actions": [], + "allow_rename": 1, + "autoname": "field:criteria_name", + "creation": "2017-05-29 01:32:43.064891", + "doctype": "DocType", + "editable_grid": 1, + "engine": "InnoDB", + "field_order": [ + "criteria_name", + "max_score", + "formula", + "weight" + ], "fields": [ { - "allow_bulk_edit": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "criteria_name", - "fieldtype": "Data", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "label": "Criteria Name", - "length": 0, - "no_copy": 0, - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 1, - "search_index": 0, - "set_only_once": 0, + "fieldname": "criteria_name", + "fieldtype": "Data", + "label": "Criteria Name", + "reqd": 1, "unique": 1 - }, + }, { - "allow_bulk_edit": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "default": "100", - "fieldname": "max_score", - "fieldtype": "Float", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 1, - "in_standard_filter": 0, - "label": "Max Score", - "length": 0, - "no_copy": 0, - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 1, - "search_index": 0, - "set_only_once": 0, - "unique": 0 - }, + "default": "100", + "fieldname": "max_score", + "fieldtype": "Float", + "in_list_view": 1, + "label": "Max Score", + "reqd": 1 + }, { - "allow_bulk_edit": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "formula", - "fieldtype": "Small Text", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 1, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 1, - "in_standard_filter": 0, - "label": "Criteria Formula", - "length": 0, - "no_copy": 0, - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 1, - "search_index": 0, - "set_only_once": 0, - "unique": 0 - }, + "fieldname": "formula", + "fieldtype": "Small Text", + "ignore_xss_filter": 1, + "in_list_view": 1, + "label": "Criteria Formula", + "reqd": 1 + }, { - "allow_bulk_edit": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "weight", - "fieldtype": "Percent", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "label": "Criteria Weight", - "length": 0, - "no_copy": 0, - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "unique": 0 + "fieldname": "weight", + "fieldtype": "Percent", + "label": "Criteria Weight" } - ], - "has_web_view": 0, - "hide_heading": 0, - "hide_toolbar": 0, - "idx": 0, - "image_view": 0, - "in_create": 0, - "is_submittable": 0, - "issingle": 0, - "istable": 0, - "max_attachments": 0, - "modified": "2019-01-22 10:47:00.000822", - "modified_by": "Administrator", - "module": "Buying", - "name": "Supplier Scorecard Criteria", - "name_case": "", - "owner": "Administrator", + ], + "links": [], + "modified": "2021-11-11 18:34:58.477648", + "modified_by": "Administrator", + "module": "Buying", + "name": "Supplier Scorecard Criteria", + "naming_rule": "By fieldname", + "owner": "Administrator", "permissions": [ { - "amend": 0, - "apply_user_permissions": 0, - "cancel": 0, - "create": 1, - "delete": 1, - "email": 1, - "export": 1, - "if_owner": 0, - "import": 0, - "permlevel": 0, - "print": 1, - "read": 1, - "report": 1, - "role": "System Manager", - "set_user_permissions": 0, - "share": 1, - "submit": 0, + "create": 1, + "delete": 1, + "email": 1, + "export": 1, + "print": 1, + "read": 1, + "report": 1, + "role": "System Manager", + "share": 1, "write": 1 } - ], - "quick_entry": 1, - "read_only": 0, - "read_only_onload": 0, - "show_name_in_global_search": 0, - "sort_field": "modified", - "sort_order": "DESC", - "track_changes": 1, - "track_seen": 0 + ], + "quick_entry": 1, + "sort_field": "modified", + "sort_order": "DESC", + "track_changes": 1 } \ No newline at end of file diff --git a/erpnext/buying/doctype/supplier_scorecard_criteria/supplier_scorecard_criteria.py b/erpnext/buying/doctype/supplier_scorecard_criteria/supplier_scorecard_criteria.py index c456377d9b7..7cd18c31e8b 100644 --- a/erpnext/buying/doctype/supplier_scorecard_criteria/supplier_scorecard_criteria.py +++ b/erpnext/buying/doctype/supplier_scorecard_criteria/supplier_scorecard_criteria.py @@ -1,8 +1,6 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2017, Frappe Technologies Pvt. Ltd. and contributors # For license information, please see license.txt -from __future__ import unicode_literals import re diff --git a/erpnext/buying/doctype/supplier_scorecard_criteria/test_supplier_scorecard_criteria.py b/erpnext/buying/doctype/supplier_scorecard_criteria/test_supplier_scorecard_criteria.py index 9fca9a9f17a..dacc982420e 100644 --- a/erpnext/buying/doctype/supplier_scorecard_criteria/test_supplier_scorecard_criteria.py +++ b/erpnext/buying/doctype/supplier_scorecard_criteria/test_supplier_scorecard_criteria.py @@ -1,7 +1,5 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2017, Frappe Technologies Pvt. Ltd. and Contributors # See license.txt -from __future__ import unicode_literals import unittest diff --git a/erpnext/buying/doctype/supplier_scorecard_period/supplier_scorecard_period.py b/erpnext/buying/doctype/supplier_scorecard_period/supplier_scorecard_period.py index b03d216ce23..c247241cf35 100644 --- a/erpnext/buying/doctype/supplier_scorecard_period/supplier_scorecard_period.py +++ b/erpnext/buying/doctype/supplier_scorecard_period/supplier_scorecard_period.py @@ -1,8 +1,6 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2017, Frappe Technologies Pvt. Ltd. and contributors # For license information, please see license.txt -from __future__ import unicode_literals import frappe from frappe import _, throw diff --git a/erpnext/buying/doctype/supplier_scorecard_period/test_supplier_scorecard_period.py b/erpnext/buying/doctype/supplier_scorecard_period/test_supplier_scorecard_period.py index de8bc0a0272..005cd791700 100644 --- a/erpnext/buying/doctype/supplier_scorecard_period/test_supplier_scorecard_period.py +++ b/erpnext/buying/doctype/supplier_scorecard_period/test_supplier_scorecard_period.py @@ -1,7 +1,5 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2017, Frappe Technologies Pvt. Ltd. and Contributors # See license.txt -from __future__ import unicode_literals import unittest diff --git a/erpnext/buying/doctype/supplier_scorecard_scoring_criteria/supplier_scorecard_scoring_criteria.py b/erpnext/buying/doctype/supplier_scorecard_scoring_criteria/supplier_scorecard_scoring_criteria.py index 79d5082ab6a..3a6de59f34b 100644 --- a/erpnext/buying/doctype/supplier_scorecard_scoring_criteria/supplier_scorecard_scoring_criteria.py +++ b/erpnext/buying/doctype/supplier_scorecard_scoring_criteria/supplier_scorecard_scoring_criteria.py @@ -1,8 +1,6 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2017, Frappe Technologies Pvt. Ltd. and contributors # For license information, please see license.txt -from __future__ import unicode_literals from frappe.model.document import Document diff --git a/erpnext/buying/doctype/supplier_scorecard_scoring_standing/supplier_scorecard_scoring_standing.py b/erpnext/buying/doctype/supplier_scorecard_scoring_standing/supplier_scorecard_scoring_standing.py index 5063b20ddbb..8d66e6414b7 100644 --- a/erpnext/buying/doctype/supplier_scorecard_scoring_standing/supplier_scorecard_scoring_standing.py +++ b/erpnext/buying/doctype/supplier_scorecard_scoring_standing/supplier_scorecard_scoring_standing.py @@ -1,8 +1,6 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2017, Frappe Technologies Pvt. Ltd. and contributors # For license information, please see license.txt -from __future__ import unicode_literals from frappe.model.document import Document diff --git a/erpnext/buying/doctype/supplier_scorecard_scoring_variable/supplier_scorecard_scoring_variable.py b/erpnext/buying/doctype/supplier_scorecard_scoring_variable/supplier_scorecard_scoring_variable.py index 476cb35e8cd..f13eb5b420c 100644 --- a/erpnext/buying/doctype/supplier_scorecard_scoring_variable/supplier_scorecard_scoring_variable.py +++ b/erpnext/buying/doctype/supplier_scorecard_scoring_variable/supplier_scorecard_scoring_variable.py @@ -1,8 +1,6 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2017, Frappe Technologies Pvt. Ltd. and contributors # For license information, please see license.txt -from __future__ import unicode_literals from frappe.model.document import Document diff --git a/erpnext/buying/doctype/supplier_scorecard_standing/supplier_scorecard_standing.py b/erpnext/buying/doctype/supplier_scorecard_standing/supplier_scorecard_standing.py index 4fc45e89c7b..11ebe6da13c 100644 --- a/erpnext/buying/doctype/supplier_scorecard_standing/supplier_scorecard_standing.py +++ b/erpnext/buying/doctype/supplier_scorecard_standing/supplier_scorecard_standing.py @@ -1,8 +1,6 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2017, Frappe Technologies Pvt. Ltd. and contributors # For license information, please see license.txt -from __future__ import unicode_literals import frappe from frappe.model.document import Document diff --git a/erpnext/buying/doctype/supplier_scorecard_standing/test_supplier_scorecard_standing.py b/erpnext/buying/doctype/supplier_scorecard_standing/test_supplier_scorecard_standing.py index 5ac5927d081..bd1b0ad7f61 100644 --- a/erpnext/buying/doctype/supplier_scorecard_standing/test_supplier_scorecard_standing.py +++ b/erpnext/buying/doctype/supplier_scorecard_standing/test_supplier_scorecard_standing.py @@ -1,7 +1,5 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2017, Frappe Technologies Pvt. Ltd. and Contributors # See license.txt -from __future__ import unicode_literals import unittest diff --git a/erpnext/buying/doctype/supplier_scorecard_variable/supplier_scorecard_variable.py b/erpnext/buying/doctype/supplier_scorecard_variable/supplier_scorecard_variable.py index 30b2a1893f1..217aadba6bd 100644 --- a/erpnext/buying/doctype/supplier_scorecard_variable/supplier_scorecard_variable.py +++ b/erpnext/buying/doctype/supplier_scorecard_variable/supplier_scorecard_variable.py @@ -1,8 +1,6 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2017, Frappe Technologies Pvt. Ltd. and contributors # For license information, please see license.txt -from __future__ import unicode_literals import sys diff --git a/erpnext/buying/doctype/supplier_scorecard_variable/test_supplier_scorecard_variable.py b/erpnext/buying/doctype/supplier_scorecard_variable/test_supplier_scorecard_variable.py index 990413cd404..4d75981125f 100644 --- a/erpnext/buying/doctype/supplier_scorecard_variable/test_supplier_scorecard_variable.py +++ b/erpnext/buying/doctype/supplier_scorecard_variable/test_supplier_scorecard_variable.py @@ -1,7 +1,5 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2017, Frappe Technologies Pvt. Ltd. and Contributors # See license.txt -from __future__ import unicode_literals import unittest diff --git a/erpnext/buying/form_tour/buying_settings/buying_settings.json b/erpnext/buying/form_tour/buying_settings/buying_settings.json new file mode 100644 index 00000000000..fa8c80d6cdf --- /dev/null +++ b/erpnext/buying/form_tour/buying_settings/buying_settings.json @@ -0,0 +1,77 @@ +{ + "creation": "2021-07-28 11:51:42.319984", + "docstatus": 0, + "doctype": "Form Tour", + "idx": 0, + "is_standard": 1, + "modified": "2021-10-05 13:06:56.414584", + "modified_by": "Administrator", + "module": "Buying", + "name": "Buying Settings", + "owner": "Administrator", + "reference_doctype": "Buying Settings", + "save_on_complete": 0, + "steps": [ + { + "description": "When a Supplier is saved, system generates a unique identity or name for that Supplier which can be used to refer the Supplier in various Buying transactions.", + "field": "", + "fieldname": "supp_master_name", + "fieldtype": "Select", + "has_next_condition": 0, + "is_table_field": 0, + "label": "Supplier Naming By", + "parent_field": "", + "position": "Bottom", + "title": "Supplier Naming By" + }, + { + "description": "Configure what should be the default value of Supplier Group when creating a new Supplier.", + "field": "", + "fieldname": "supplier_group", + "fieldtype": "Link", + "has_next_condition": 0, + "is_table_field": 0, + "label": "Default Supplier Group", + "parent_field": "", + "position": "Right", + "title": "Default Supplier Group" + }, + { + "description": "Item prices will be fetched from this Price List.", + "field": "", + "fieldname": "buying_price_list", + "fieldtype": "Link", + "has_next_condition": 0, + "is_table_field": 0, + "label": "Default Buying Price List", + "parent_field": "", + "position": "Bottom", + "title": "Default Buying Price List" + }, + { + "description": "If this option is configured \"Yes\", ERPNext will prevent you from creating a Purchase Invoice or a Purchase Receipt directly without creating a Purchase Order first.", + "field": "", + "fieldname": "po_required", + "fieldtype": "Select", + "has_next_condition": 0, + "is_table_field": 0, + "label": "Is Purchase Order Required for Purchase Invoice & Receipt Creation?", + "parent_field": "", + "position": "Bottom", + "title": "Purchase Order Required" + }, + { + "description": "If this option is configured \"Yes\", ERPNext will prevent you from creating a Purchase Invoice without creating a Purchase Receipt first.", + "field": "", + "fieldname": "pr_required", + "fieldtype": "Select", + "has_next_condition": 0, + "is_table_field": 0, + "label": "Is Purchase Receipt Required for Purchase Invoice Creation?", + "parent_field": "", + "position": "Bottom", + "title": "Purchase Receipt Required" + } + ], + "title": "Buying Settings" +} \ No newline at end of file diff --git a/erpnext/buying/form_tour/purchase_order/purchase_order.json b/erpnext/buying/form_tour/purchase_order/purchase_order.json new file mode 100644 index 00000000000..3cc88fbf4fe --- /dev/null +++ b/erpnext/buying/form_tour/purchase_order/purchase_order.json @@ -0,0 +1,82 @@ +{ + "creation": "2021-07-29 14:11:58.271113", + "docstatus": 0, + "doctype": "Form Tour", + "idx": 0, + "is_standard": 1, + "modified": "2021-10-05 13:11:31.436135", + "modified_by": "Administrator", + "module": "Buying", + "name": "Purchase Order", + "owner": "Administrator", + "reference_doctype": "Purchase Order", + "save_on_complete": 1, + "steps": [ + { + "description": "Select a Supplier", + "field": "", + "fieldname": "supplier", + "fieldtype": "Link", + "has_next_condition": 0, + "is_table_field": 0, + "label": "Supplier", + "parent_field": "", + "position": "Right", + "title": "Supplier" + }, + { + "description": "Set the \"Required By\" date for the materials. This sets the \"Required By\" date for all the items.", + "field": "", + "fieldname": "schedule_date", + "fieldtype": "Date", + "has_next_condition": 0, + "is_table_field": 0, + "label": "Required By", + "parent_field": "", + "position": "Left", + "title": "Required By" + }, + { + "description": "Items to be purchased can be added here.", + "field": "", + "fieldname": "items", + "fieldtype": "Table", + "has_next_condition": 0, + "is_table_field": 0, + "label": "Items", + "parent_field": "", + "position": "Bottom", + "title": "Items Table" + }, + { + "child_doctype": "Purchase Order Item", + "description": "Enter the Item Code.", + "field": "", + "fieldname": "item_code", + "fieldtype": "Link", + "has_next_condition": 1, + "is_table_field": 1, + "label": "Item Code", + "next_step_condition": "eval: doc.item_code", + "parent_field": "", + "parent_fieldname": "items", + "position": "Right", + "title": "Item Code" + }, + { + "child_doctype": "Purchase Order Item", + "description": "Enter the required quantity for the material.", + "field": "", + "fieldname": "qty", + "fieldtype": "Float", + "has_next_condition": 0, + "is_table_field": 1, + "label": "Quantity", + "parent_field": "", + "parent_fieldname": "items", + "position": "Bottom", + "title": "Quantity" + } + ], + "title": "Purchase Order" +} \ No newline at end of file diff --git a/erpnext/buying/module_onboarding/buying/buying.json b/erpnext/buying/module_onboarding/buying/buying.json index 887f85b82d1..84e97a2d4d2 100644 --- a/erpnext/buying/module_onboarding/buying/buying.json +++ b/erpnext/buying/module_onboarding/buying/buying.json @@ -19,7 +19,7 @@ "documentation_url": "https://docs.erpnext.com/docs/user/manual/en/buying", "idx": 0, "is_complete": 0, - "modified": "2020-07-08 14:05:28.273641", + "modified": "2021-08-24 18:13:42.463776", "modified_by": "Administrator", "module": "Buying", "name": "Buying", @@ -28,23 +28,11 @@ { "step": "Introduction to Buying" }, - { - "step": "Create a Supplier" - }, - { - "step": "Setup your Warehouse" - }, - { - "step": "Create a Product" - }, { "step": "Create a Material Request" }, { "step": "Create your first Purchase Order" - }, - { - "step": "Buying Settings" } ], "subtitle": "Products, Purchases, Analysis, and more.", diff --git a/erpnext/buying/onboarding_step/create_a_material_request/create_a_material_request.json b/erpnext/buying/onboarding_step/create_a_material_request/create_a_material_request.json index 9dc493dd499..28e86ab0641 100644 --- a/erpnext/buying/onboarding_step/create_a_material_request/create_a_material_request.json +++ b/erpnext/buying/onboarding_step/create_a_material_request/create_a_material_request.json @@ -1,19 +1,21 @@ { - "action": "Create Entry", + "action": "Show Form Tour", + "action_label": "Let\u2019s create your first Material Request", "creation": "2020-05-15 14:39:09.818764", + "description": "# Track Material Request\n\n\nAlso known as Purchase Request or an Indent, is a document identifying a requirement of a set of items (products or services) for various purposes like procurement, transfer, issue, or manufacturing. Once the Material Request is validated, a purchase manager can take the next actions for purchasing items like requesting RFQ from a supplier or directly placing an order with an identified Supplier.\n\n", "docstatus": 0, "doctype": "Onboarding Step", "idx": 0, "is_complete": 0, - "is_mandatory": 1, "is_single": 0, "is_skipped": 0, - "modified": "2020-05-15 14:39:09.818764", + "modified": "2021-08-24 18:08:08.347501", "modified_by": "Administrator", "name": "Create a Material Request", "owner": "Administrator", "reference_document": "Material Request", + "show_form_tour": 1, "show_full_form": 1, - "title": "Create a Material Request", + "title": "Track Material Request", "validate_action": 1 } \ No newline at end of file diff --git a/erpnext/buying/onboarding_step/create_your_first_purchase_order/create_your_first_purchase_order.json b/erpnext/buying/onboarding_step/create_your_first_purchase_order/create_your_first_purchase_order.json index 9dbed239789..18a39315861 100644 --- a/erpnext/buying/onboarding_step/create_your_first_purchase_order/create_your_first_purchase_order.json +++ b/erpnext/buying/onboarding_step/create_your_first_purchase_order/create_your_first_purchase_order.json @@ -1,19 +1,21 @@ { - "action": "Create Entry", + "action": "Show Form Tour", + "action_label": "Let\u2019s create your first Purchase Order", "creation": "2020-05-12 18:17:49.976035", + "description": "# Create first Purchase Order\n\nPurchase Order is at the heart of your buying transactions. In ERPNext, Purchase Order can can be created against a Purchase Material Request (indent) and Supplier Quotation as well. Purchase Orders is also linked to Purchase Receipt and Purchase Invoices, allowing you to keep a birds-eye view on your purchase deals.\n\n", "docstatus": 0, "doctype": "Onboarding Step", "idx": 0, "is_complete": 0, - "is_mandatory": 0, "is_single": 0, "is_skipped": 0, - "modified": "2020-05-12 18:31:56.856112", + "modified": "2021-08-24 18:08:08.936484", "modified_by": "Administrator", "name": "Create your first Purchase Order", "owner": "Administrator", "reference_document": "Purchase Order", + "show_form_tour": 0, "show_full_form": 0, - "title": "Create your first Purchase Order", + "title": "Create first Purchase Order", "validate_action": 1 } \ No newline at end of file diff --git a/erpnext/buying/onboarding_step/introduction_to_buying/introduction_to_buying.json b/erpnext/buying/onboarding_step/introduction_to_buying/introduction_to_buying.json index fd98fddafae..01ac8b81760 100644 --- a/erpnext/buying/onboarding_step/introduction_to_buying/introduction_to_buying.json +++ b/erpnext/buying/onboarding_step/introduction_to_buying/introduction_to_buying.json @@ -1,19 +1,22 @@ { - "action": "Watch Video", + "action": "Show Form Tour", + "action_label": "Let\u2019s walk-through few Buying Settings", "creation": "2020-05-06 15:37:09.477765", + "description": "# Buying Settings\n\n\nBuying module\u2019s features are highly configurable as per your business needs. Buying Settings is the place where you can set your preferences for:\n\n- Supplier naming and default values\n- Billing and shipping preference in buying transactions\n\n\n", "docstatus": 0, "doctype": "Onboarding Step", "idx": 0, "is_complete": 0, - "is_mandatory": 0, - "is_single": 0, + "is_single": 1, "is_skipped": 0, - "modified": "2020-05-12 18:25:08.509900", + "modified": "2021-08-24 18:08:08.345735", "modified_by": "Administrator", "name": "Introduction to Buying", "owner": "Administrator", - "show_full_form": 0, - "title": "Introduction to Buying", + "reference_document": "Buying Settings", + "show_form_tour": 1, + "show_full_form": 1, + "title": "Buying Settings", "validate_action": 1, "video_url": "https://youtu.be/efFajTTQBa8" } \ No newline at end of file diff --git a/erpnext/buying/page/__init__.py b/erpnext/buying/page/__init__.py index baffc488252..e69de29bb2d 100644 --- a/erpnext/buying/page/__init__.py +++ b/erpnext/buying/page/__init__.py @@ -1 +0,0 @@ -from __future__ import unicode_literals diff --git a/erpnext/healthcare/dashboard_chart_source/department_wise_patient_appointments/__init__.py b/erpnext/buying/print_format_field_template/__init__.py similarity index 100% rename from erpnext/healthcare/dashboard_chart_source/department_wise_patient_appointments/__init__.py rename to erpnext/buying/print_format_field_template/__init__.py diff --git a/erpnext/healthcare/doctype/__init__.py b/erpnext/buying/print_format_field_template/purchase_order_taxes/__init__.py similarity index 100% rename from erpnext/healthcare/doctype/__init__.py rename to erpnext/buying/print_format_field_template/purchase_order_taxes/__init__.py diff --git a/erpnext/buying/print_format_field_template/purchase_order_taxes/purchase_order_taxes.json b/erpnext/buying/print_format_field_template/purchase_order_taxes/purchase_order_taxes.json new file mode 100644 index 00000000000..73b77308949 --- /dev/null +++ b/erpnext/buying/print_format_field_template/purchase_order_taxes/purchase_order_taxes.json @@ -0,0 +1,16 @@ +{ + "creation": "2021-10-19 18:07:19.253457", + "docstatus": 0, + "doctype": "Print Format Field Template", + "document_type": "Purchase Order", + "field": "taxes", + "idx": 0, + "modified": "2021-10-19 18:07:19.253457", + "modified_by": "Administrator", + "module": "Buying", + "name": "Purchase Order Taxes", + "owner": "Administrator", + "standard": 1, + "template": "", + "template_file": "templates/print_formats/includes/taxes_and_charges.html" +} \ No newline at end of file diff --git a/erpnext/healthcare/doctype/antibiotic/__init__.py b/erpnext/buying/print_format_field_template/supplier_quotation_taxes/__init__.py similarity index 100% rename from erpnext/healthcare/doctype/antibiotic/__init__.py rename to erpnext/buying/print_format_field_template/supplier_quotation_taxes/__init__.py diff --git a/erpnext/buying/print_format_field_template/supplier_quotation_taxes/supplier_quotation_taxes.json b/erpnext/buying/print_format_field_template/supplier_quotation_taxes/supplier_quotation_taxes.json new file mode 100644 index 00000000000..2be17a1b012 --- /dev/null +++ b/erpnext/buying/print_format_field_template/supplier_quotation_taxes/supplier_quotation_taxes.json @@ -0,0 +1,16 @@ +{ + "creation": "2021-10-19 18:09:08.103919", + "docstatus": 0, + "doctype": "Print Format Field Template", + "document_type": "Supplier Quotation", + "field": "taxes", + "idx": 0, + "modified": "2021-10-19 18:09:08.103919", + "modified_by": "Administrator", + "module": "Buying", + "name": "Supplier Quotation Taxes", + "owner": "Administrator", + "standard": 1, + "template": "", + "template_file": "templates/print_formats/includes/taxes_and_charges.html" +} \ No newline at end of file diff --git a/erpnext/buying/report/procurement_tracker/procurement_tracker.py b/erpnext/buying/report/procurement_tracker/procurement_tracker.py index cb992342820..295a19d052e 100644 --- a/erpnext/buying/report/procurement_tracker/procurement_tracker.py +++ b/erpnext/buying/report/procurement_tracker/procurement_tracker.py @@ -1,7 +1,6 @@ # Copyright (c) 2013, Frappe Technologies Pvt. Ltd. and contributors # For license information, please see license.txt -from __future__ import unicode_literals import frappe from frappe import _ diff --git a/erpnext/buying/report/procurement_tracker/test_procurement_tracker.py b/erpnext/buying/report/procurement_tracker/test_procurement_tracker.py index a5b09473a05..84de8c67438 100644 --- a/erpnext/buying/report/procurement_tracker/test_procurement_tracker.py +++ b/erpnext/buying/report/procurement_tracker/test_procurement_tracker.py @@ -1,7 +1,6 @@ # Copyright (c) 2013, Frappe Technologies Pvt. Ltd. and contributors # For license information, please see license.txt -from __future__ import unicode_literals import unittest from datetime import datetime @@ -45,7 +44,6 @@ class TestProcurementTracker(unittest.TestCase): pr = make_purchase_receipt(po.name) pr.get("items")[0].cost_center = "Main - _TPC" pr.submit() - frappe.db.commit() date_obj = datetime.date(datetime.now()) po.load_from_db() diff --git a/erpnext/buying/report/purchase_analytics/purchase_analytics.py b/erpnext/buying/report/purchase_analytics/purchase_analytics.py index bef66da4818..6a84d913227 100644 --- a/erpnext/buying/report/purchase_analytics/purchase_analytics.py +++ b/erpnext/buying/report/purchase_analytics/purchase_analytics.py @@ -1,7 +1,6 @@ # Copyright (c) 2013, Frappe Technologies Pvt. Ltd. and contributors # For license information, please see license.txt -from __future__ import unicode_literals from erpnext.selling.report.sales_analytics.sales_analytics import Analytics diff --git a/erpnext/buying/report/purchase_order_analysis/purchase_order_analysis.js b/erpnext/buying/report/purchase_order_analysis/purchase_order_analysis.js index 701da4380aa..ca3be03da6e 100644 --- a/erpnext/buying/report/purchase_order_analysis/purchase_order_analysis.js +++ b/erpnext/buying/report/purchase_order_analysis/purchase_order_analysis.js @@ -30,7 +30,14 @@ frappe.query_reports["Purchase Order Analysis"] = { "default": frappe.datetime.get_today() }, { - "fieldname": "purchase_order", + "fieldname":"project", + "label": __("Project"), + "fieldtype": "Link", + "width": "80", + "options": "Project" + }, + { + "fieldname": "name", "label": __("Purchase Order"), "fieldtype": "Link", "width": "80", diff --git a/erpnext/buying/report/purchase_order_analysis/purchase_order_analysis.py b/erpnext/buying/report/purchase_order_analysis/purchase_order_analysis.py index 5d59456550b..9dd912118ff 100644 --- a/erpnext/buying/report/purchase_order_analysis/purchase_order_analysis.py +++ b/erpnext/buying/report/purchase_order_analysis/purchase_order_analysis.py @@ -1,7 +1,6 @@ # Copyright (c) 2013, Frappe Technologies Pvt. Ltd. and contributors # For license information, please see license.txt -from __future__ import unicode_literals import copy @@ -41,15 +40,16 @@ def get_conditions(filters): if filters.get("from_date") and filters.get("to_date"): conditions += " and po.transaction_date between %(from_date)s and %(to_date)s" - if filters.get("company"): - conditions += " and po.company = %(company)s" + for field in ['company', 'name']: + if filters.get(field): + conditions += f" and po.{field} = %({field})s" - if filters.get("purchase_order"): - conditions += " and po.name = %(purchase_order)s" - - if filters.get("status"): + if filters.get('status'): conditions += " and po.status in %(status)s" + if filters.get('project'): + conditions += " and poi.project = %(project)s" + return conditions def get_data(conditions, filters): @@ -57,6 +57,7 @@ def get_data(conditions, filters): SELECT po.transaction_date as date, poi.schedule_date as required_date, + poi.project, po.name as purchase_order, po.status, po.supplier, poi.item_code, poi.qty, poi.received_qty, @@ -175,6 +176,12 @@ def get_columns(filters): "fieldtype": "Link", "options": "Supplier", "width": 130 + },{ + "label": _("Project"), + "fieldname": "project", + "fieldtype": "Link", + "options": "Project", + "width": 130 }] if not filters.get("group_by_po"): diff --git a/erpnext/buying/report/purchase_order_trends/purchase_order_trends.py b/erpnext/buying/report/purchase_order_trends/purchase_order_trends.py index 9781480afa7..21643a896b7 100644 --- a/erpnext/buying/report/purchase_order_trends/purchase_order_trends.py +++ b/erpnext/buying/report/purchase_order_trends/purchase_order_trends.py @@ -1,7 +1,6 @@ # Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors # License: GNU General Public License v3. See license.txt -from __future__ import unicode_literals from frappe import _ diff --git a/erpnext/buying/report/requested_items_to_order_and_receive/requested_items_to_order_and_receive.py b/erpnext/buying/report/requested_items_to_order_and_receive/requested_items_to_order_and_receive.py index 42cc6ebc0a6..f98e5f12c2d 100644 --- a/erpnext/buying/report/requested_items_to_order_and_receive/requested_items_to_order_and_receive.py +++ b/erpnext/buying/report/requested_items_to_order_and_receive/requested_items_to_order_and_receive.py @@ -1,7 +1,6 @@ # Copyright (c) 2013, Frappe Technologies Pvt. Ltd. and contributors # For license information, please see license.txt -from __future__ import unicode_literals import copy diff --git a/erpnext/buying/report/subcontract_order_summary/subcontract_order_summary.py b/erpnext/buying/report/subcontract_order_summary/subcontract_order_summary.py index 202d3641859..8e5c2f9a30d 100644 --- a/erpnext/buying/report/subcontract_order_summary/subcontract_order_summary.py +++ b/erpnext/buying/report/subcontract_order_summary/subcontract_order_summary.py @@ -1,7 +1,6 @@ # Copyright (c) 2013, Frappe Technologies Pvt. Ltd. and contributors # For license information, please see license.txt -from __future__ import unicode_literals import frappe from frappe import _ diff --git a/erpnext/buying/report/subcontracted_item_to_be_received/subcontracted_item_to_be_received.py b/erpnext/buying/report/subcontracted_item_to_be_received/subcontracted_item_to_be_received.py index 9299cca0da4..67e275f9851 100644 --- a/erpnext/buying/report/subcontracted_item_to_be_received/subcontracted_item_to_be_received.py +++ b/erpnext/buying/report/subcontracted_item_to_be_received/subcontracted_item_to_be_received.py @@ -1,7 +1,6 @@ # Copyright (c) 2013, Frappe Technologies Pvt. Ltd. and contributors # For license information, please see license.txt -from __future__ import unicode_literals import frappe from frappe import _ diff --git a/erpnext/buying/report/subcontracted_item_to_be_received/test_subcontracted_item_to_be_received.py b/erpnext/buying/report/subcontracted_item_to_be_received/test_subcontracted_item_to_be_received.py index 7aeae451645..144523ad522 100644 --- a/erpnext/buying/report/subcontracted_item_to_be_received/test_subcontracted_item_to_be_received.py +++ b/erpnext/buying/report/subcontracted_item_to_be_received/test_subcontracted_item_to_be_received.py @@ -2,7 +2,6 @@ # Embedded file name: /Users/anuragmishra/frappe-develop/apps/erpnext/erpnext/buying/report/subcontracted_item_to_be_received/test_subcontracted_item_to_be_received.py # Compiled at: 2019-05-06 09:51:46 # Decompiled by https://python-decompiler.com -from __future__ import unicode_literals import unittest diff --git a/erpnext/buying/report/subcontracted_raw_materials_to_be_transferred/subcontracted_raw_materials_to_be_transferred.py b/erpnext/buying/report/subcontracted_raw_materials_to_be_transferred/subcontracted_raw_materials_to_be_transferred.py index a8fad967d40..6b605add4c7 100644 --- a/erpnext/buying/report/subcontracted_raw_materials_to_be_transferred/subcontracted_raw_materials_to_be_transferred.py +++ b/erpnext/buying/report/subcontracted_raw_materials_to_be_transferred/subcontracted_raw_materials_to_be_transferred.py @@ -1,7 +1,6 @@ # Copyright (c) 2013, Frappe Technologies Pvt. Ltd. and contributors # For license information, please see license.txt -from __future__ import unicode_literals import frappe from frappe import _ diff --git a/erpnext/buying/report/subcontracted_raw_materials_to_be_transferred/test_subcontracted_raw_materials_to_be_transferred.py b/erpnext/buying/report/subcontracted_raw_materials_to_be_transferred/test_subcontracted_raw_materials_to_be_transferred.py index dcdc5e36abe..3c203ac23fa 100644 --- a/erpnext/buying/report/subcontracted_raw_materials_to_be_transferred/test_subcontracted_raw_materials_to_be_transferred.py +++ b/erpnext/buying/report/subcontracted_raw_materials_to_be_transferred/test_subcontracted_raw_materials_to_be_transferred.py @@ -2,7 +2,6 @@ # Embedded file name: /Users/anuragmishra/frappe-develop/apps/erpnext/erpnext/buying/report/subcontracted_raw_materials_to_be_transferred/test_subcontracted_raw_materials_to_be_transferred.py # Compiled at: 2019-05-06 10:24:35 # Decompiled by https://python-decompiler.com -from __future__ import unicode_literals import json import unittest diff --git a/erpnext/buying/report/supplier_quotation_comparison/supplier_quotation_comparison.py b/erpnext/buying/report/supplier_quotation_comparison/supplier_quotation_comparison.py index 62b83ede04b..65f9ce3c57e 100644 --- a/erpnext/buying/report/supplier_quotation_comparison/supplier_quotation_comparison.py +++ b/erpnext/buying/report/supplier_quotation_comparison/supplier_quotation_comparison.py @@ -1,7 +1,6 @@ # Copyright (c) 2013, Frappe Technologies Pvt. Ltd. and contributors # For license information, please see license.txt -from __future__ import unicode_literals from collections import defaultdict diff --git a/erpnext/buying/utils.py b/erpnext/buying/utils.py index 81d995ce8de..66c60d56379 100644 --- a/erpnext/buying/utils.py +++ b/erpnext/buying/utils.py @@ -1,7 +1,6 @@ # Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors # License: GNU General Public License v3. See license.txt -from __future__ import unicode_literals import json diff --git a/erpnext/buying/workspace/buying/buying.json b/erpnext/buying/workspace/buying/buying.json index 6c91e816954..380ef3639f6 100644 --- a/erpnext/buying/workspace/buying/buying.json +++ b/erpnext/buying/workspace/buying/buying.json @@ -1,27 +1,18 @@ { - "cards_label": "", - "category": "", "charts": [ { "chart_name": "Purchase Order Trends", "label": "Purchase Order Trends" } ], - "charts_label": "", "content": "[{\"type\": \"onboarding\", \"data\": {\"onboarding_name\":\"Buying\", \"col\": 12}}, {\"type\": \"chart\", \"data\": {\"chart_name\": \"Purchase Order Trends\", \"col\": 12}}, {\"type\": \"spacer\", \"data\": {\"col\": 12}}, {\"type\": \"header\", \"data\": {\"text\": \"Your Shortcuts\", \"level\": 4, \"col\": 12}}, {\"type\": \"shortcut\", \"data\": {\"shortcut_name\": \"Item\", \"col\": 4}}, {\"type\": \"shortcut\", \"data\": {\"shortcut_name\": \"Material Request\", \"col\": 4}}, {\"type\": \"shortcut\", \"data\": {\"shortcut_name\": \"Purchase Order\", \"col\": 4}}, {\"type\": \"shortcut\", \"data\": {\"shortcut_name\": \"Purchase Analytics\", \"col\": 4}}, {\"type\": \"shortcut\", \"data\": {\"shortcut_name\": \"Purchase Order Analysis\", \"col\": 4}}, {\"type\": \"shortcut\", \"data\": {\"shortcut_name\": \"Dashboard\", \"col\": 4}}, {\"type\": \"spacer\", \"data\": {\"col\": 12}}, {\"type\": \"header\", \"data\": {\"text\": \"Reports & Masters\", \"level\": 4, \"col\": 12}}, {\"type\": \"card\", \"data\": {\"card_name\": \"Buying\", \"col\": 4}}, {\"type\": \"card\", \"data\": {\"card_name\": \"Items & Pricing\", \"col\": 4}}, {\"type\": \"card\", \"data\": {\"card_name\": \"Settings\", \"col\": 4}}, {\"type\": \"card\", \"data\": {\"card_name\": \"Supplier\", \"col\": 4}}, {\"type\": \"card\", \"data\": {\"card_name\": \"Supplier Scorecard\", \"col\": 4}}, {\"type\": \"card\", \"data\": {\"card_name\": \"Key Reports\", \"col\": 4}}, {\"type\": \"card\", \"data\": {\"card_name\": \"Other Reports\", \"col\": 4}}, {\"type\": \"card\", \"data\": {\"card_name\": \"Regional\", \"col\": 4}}]", "creation": "2020-01-28 11:50:26.195467", - "developer_mode_only": 0, - "disable_user_customization": 0, "docstatus": 0, "doctype": "Workspace", - "extends": "", - "extends_another_page": 0, "for_user": "", "hide_custom": 0, "icon": "buying", "idx": 0, - "is_default": 0, - "is_standard": 0, "label": "Buying", "links": [ { @@ -518,15 +509,12 @@ "type": "Link" } ], - "modified": "2021-08-05 12:15:56.218427", + "modified": "2021-08-05 12:15:56.218428", "modified_by": "Administrator", "module": "Buying", "name": "Buying", - "onboarding": "Buying", "owner": "Administrator", "parent_page": "", - "pin_to_bottom": 0, - "pin_to_top": 0, "public": 1, "restrict_to_domain": "", "roles": [], @@ -572,6 +560,5 @@ "type": "Dashboard" } ], - "shortcuts_label": "", "title": "Buying" } \ No newline at end of file diff --git a/erpnext/commands/__init__.py b/erpnext/commands/__init__.py index f3bf11ad652..59311192148 100644 --- a/erpnext/commands/__init__.py +++ b/erpnext/commands/__init__.py @@ -1,8 +1,6 @@ # Copyright (c) 2015, Web Notes Technologies Pvt. Ltd. and Contributors # MIT License. See license.txt -from __future__ import absolute_import, print_function, unicode_literals - import click import frappe from frappe.commands import get_site, pass_context diff --git a/erpnext/communication/doctype/communication_medium/communication_medium.py b/erpnext/communication/doctype/communication_medium/communication_medium.py index b15c3bed71b..6dfdb73b858 100644 --- a/erpnext/communication/doctype/communication_medium/communication_medium.py +++ b/erpnext/communication/doctype/communication_medium/communication_medium.py @@ -1,8 +1,6 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2019, Frappe Technologies Pvt. Ltd. and contributors # For license information, please see license.txt -from __future__ import unicode_literals # import frappe from frappe.model.document import Document diff --git a/erpnext/communication/doctype/communication_medium_timeslot/communication_medium_timeslot.py b/erpnext/communication/doctype/communication_medium_timeslot/communication_medium_timeslot.py index 5189b09dc3e..b65eba75ed0 100644 --- a/erpnext/communication/doctype/communication_medium_timeslot/communication_medium_timeslot.py +++ b/erpnext/communication/doctype/communication_medium_timeslot/communication_medium_timeslot.py @@ -1,8 +1,6 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2019, Frappe Technologies Pvt. Ltd. and contributors # For license information, please see license.txt -from __future__ import unicode_literals # import frappe from frappe.model.document import Document diff --git a/erpnext/config/education.py b/erpnext/config/education.py index ecd771f608c..d718a942527 100644 --- a/erpnext/config/education.py +++ b/erpnext/config/education.py @@ -1,5 +1,3 @@ -from __future__ import unicode_literals - from frappe import _ diff --git a/erpnext/config/projects.py b/erpnext/config/projects.py index d4d4a72a5d1..f4675e749a8 100644 --- a/erpnext/config/projects.py +++ b/erpnext/config/projects.py @@ -1,5 +1,3 @@ -from __future__ import unicode_literals - from frappe import _ diff --git a/erpnext/controllers/accounts_controller.py b/erpnext/controllers/accounts_controller.py index 515d6fdef55..77503a8ee53 100644 --- a/erpnext/controllers/accounts_controller.py +++ b/erpnext/controllers/accounts_controller.py @@ -1,7 +1,6 @@ # Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors # License: GNU General Public License v3. See license.txt -from __future__ import unicode_literals import json @@ -21,7 +20,6 @@ from frappe.utils import ( nowdate, today, ) -from six import text_type import erpnext from erpnext.accounts.doctype.accounting_dimension.accounting_dimension import ( @@ -685,13 +683,17 @@ class AccountsController(TransactionBase): .format(d.reference_name, d.against_order)) def set_advance_gain_or_loss(self): - if not self.get("advances"): + if self.get('conversion_rate') == 1 or not self.get("advances"): + return + + is_purchase_invoice = self.doctype == 'Purchase Invoice' + party_account = self.credit_to if is_purchase_invoice else self.debit_to + if get_account_currency(party_account) != self.currency: return for d in self.get("advances"): advance_exchange_rate = d.ref_exchange_rate - if (d.allocated_amount and self.conversion_rate != 1 - and self.conversion_rate != advance_exchange_rate): + if (d.allocated_amount and self.conversion_rate != advance_exchange_rate): base_allocated_amount_in_ref_rate = advance_exchange_rate * d.allocated_amount base_allocated_amount_in_inv_rate = self.conversion_rate * d.allocated_amount @@ -710,7 +712,7 @@ class AccountsController(TransactionBase): gain_loss_account = frappe.db.get_value('Company', self.company, 'exchange_gain_loss_account') if not gain_loss_account: - frappe.throw(_("Please set Default Exchange Gain/Loss Account in Company {}") + frappe.throw(_("Please set default Exchange Gain/Loss Account in Company {}") .format(self.get('company'))) account_currency = get_account_currency(gain_loss_account) if account_currency != self.company_currency: @@ -729,7 +731,7 @@ class AccountsController(TransactionBase): "against": party, dr_or_cr + "_in_account_currency": abs(d.exchange_gain_loss), dr_or_cr: abs(d.exchange_gain_loss), - "cost_center": self.cost_center, + "cost_center": self.cost_center or erpnext.get_default_cost_center(self.company), "project": self.project }, item=d) ) @@ -811,6 +813,38 @@ class AccountsController(TransactionBase): if frappe.db.get_single_value('Accounts Settings', 'unlink_advance_payment_on_cancelation_of_order'): unlink_ref_doc_from_payment_entries(self) + if self.doctype == "Sales Order": + self.unlink_ref_doc_from_po() + + def unlink_ref_doc_from_po(self): + so_items = [] + for item in self.items: + so_items.append(item.name) + + linked_po = list(set(frappe.get_all( + 'Purchase Order Item', + filters = { + 'sales_order': self.name, + 'sales_order_item': ['in', so_items], + 'docstatus': ['<', 2] + }, + pluck='parent' + ))) + + if linked_po: + frappe.db.set_value( + 'Purchase Order Item', { + 'sales_order': self.name, + 'sales_order_item': ['in', so_items], + 'docstatus': ['<', 2] + },{ + 'sales_order': None, + 'sales_order_item': None + } + ) + + frappe.msgprint(_("Purchase Orders {0} are un-linked").format("\n".join(linked_po))) + def get_tax_map(self): tax_map = {} for tax in self.get('taxes'): @@ -986,42 +1020,55 @@ class AccountsController(TransactionBase): item_allowance = {} global_qty_allowance, global_amount_allowance = None, None + role_allowed_to_over_bill = frappe.db.get_single_value('Accounts Settings', 'role_allowed_to_over_bill') + user_roles = frappe.get_roles() + + total_overbilled_amt = 0.0 + for item in self.get("items"): - if item.get(item_ref_dn): - ref_amt = flt(frappe.db.get_value(ref_dt + " Item", - item.get(item_ref_dn), based_on), self.precision(based_on, item)) - if not ref_amt: - frappe.msgprint( - _("Warning: System will not check overbilling since amount for Item {0} in {1} is zero") - .format(item.item_code, ref_dt)) - else: - already_billed = frappe.db.sql(""" - select sum(%s) - from `tab%s` - where %s=%s and docstatus=1 and parent != %s - """ % (based_on, self.doctype + " Item", item_ref_dn, '%s', '%s'), - (item.get(item_ref_dn), self.name))[0][0] + if not item.get(item_ref_dn): + continue - total_billed_amt = flt(flt(already_billed) + flt(item.get(based_on)), - self.precision(based_on, item)) + ref_amt = flt(frappe.db.get_value(ref_dt + " Item", + item.get(item_ref_dn), based_on), self.precision(based_on, item)) + if not ref_amt: + frappe.msgprint( + _("System will not check overbilling since amount for Item {0} in {1} is zero") + .format(item.item_code, ref_dt), title=_("Warning"), indicator="orange") + continue - allowance, item_allowance, global_qty_allowance, global_amount_allowance = \ - get_allowance_for(item.item_code, item_allowance, global_qty_allowance, global_amount_allowance, "amount") + already_billed = frappe.db.sql(""" + select sum(%s) + from `tab%s` + where %s=%s and docstatus=1 and parent != %s + """ % (based_on, self.doctype + " Item", item_ref_dn, '%s', '%s'), + (item.get(item_ref_dn), self.name))[0][0] - max_allowed_amt = flt(ref_amt * (100 + allowance) / 100) + total_billed_amt = flt(flt(already_billed) + flt(item.get(based_on)), + self.precision(based_on, item)) - if total_billed_amt < 0 and max_allowed_amt < 0: - # while making debit note against purchase return entry(purchase receipt) getting overbill error - total_billed_amt = abs(total_billed_amt) - max_allowed_amt = abs(max_allowed_amt) + allowance, item_allowance, global_qty_allowance, global_amount_allowance = \ + get_allowance_for(item.item_code, item_allowance, global_qty_allowance, global_amount_allowance, "amount") - role_allowed_to_over_bill = frappe.db.get_single_value('Accounts Settings', 'role_allowed_to_over_bill') + max_allowed_amt = flt(ref_amt * (100 + allowance) / 100) - if total_billed_amt - max_allowed_amt > 0.01 and role_allowed_to_over_bill not in frappe.get_roles(): - if self.doctype != "Purchase Invoice": - self.throw_overbill_exception(item, max_allowed_amt) - elif not cint(frappe.db.get_single_value("Buying Settings", "bill_for_rejected_quantity_in_purchase_invoice")): - self.throw_overbill_exception(item, max_allowed_amt) + if total_billed_amt < 0 and max_allowed_amt < 0: + # while making debit note against purchase return entry(purchase receipt) getting overbill error + total_billed_amt = abs(total_billed_amt) + max_allowed_amt = abs(max_allowed_amt) + + overbill_amt = total_billed_amt - max_allowed_amt + total_overbilled_amt += overbill_amt + + if overbill_amt > 0.01 and role_allowed_to_over_bill not in user_roles: + if self.doctype != "Purchase Invoice": + self.throw_overbill_exception(item, max_allowed_amt) + elif not cint(frappe.db.get_single_value("Buying Settings", "bill_for_rejected_quantity_in_purchase_invoice")): + self.throw_overbill_exception(item, max_allowed_amt) + + if role_allowed_to_over_bill in user_roles and total_overbilled_amt > 0.1: + frappe.msgprint(_("Overbilling of {} ignored because you have {} role.") + .format(total_overbilled_amt, role_allowed_to_over_bill), indicator="orange", alert=True) def throw_overbill_exception(self, item, max_allowed_amt): frappe.throw(_("Cannot overbill for Item {0} in row {1} more than {2}. To allow over-billing, please set allowance in Accounts Settings") @@ -1038,7 +1085,7 @@ class AccountsController(TransactionBase): stock_items = [r[0] for r in frappe.db.sql(""" select name from `tabItem` where name in (%s) and is_stock_item=1 - """ % (", ".join((["%s"] * len(item_codes))),), item_codes)] + """ % (", ".join(["%s"] * len(item_codes)),), item_codes)] return stock_items @@ -1343,8 +1390,8 @@ class AccountsController(TransactionBase): total = 0 base_total = 0 for d in self.get("payment_schedule"): - total += flt(d.payment_amount) - base_total += flt(d.base_payment_amount) + total += flt(d.payment_amount, d.precision("payment_amount")) + base_total += flt(d.base_payment_amount, d.precision("base_payment_amount")) base_grand_total = self.get("base_rounded_total") or self.base_grand_total grand_total = self.get("rounded_total") or self.grand_total @@ -1360,8 +1407,9 @@ class AccountsController(TransactionBase): else: grand_total -= self.get("total_advance") base_grand_total = flt(grand_total * self.get("conversion_rate"), self.precision("base_grand_total")) - if total != flt(grand_total, self.precision("grand_total")) or \ - base_total != flt(base_grand_total, self.precision("base_grand_total")): + + if flt(total, self.precision("grand_total")) - flt(grand_total, self.precision("grand_total")) > 0.1 or \ + flt(base_total, self.precision("base_grand_total")) - flt(base_grand_total, self.precision("base_grand_total")) > 0.1: frappe.throw(_("Total Payment Amount in Payment Schedule must be equal to Grand / Rounded Total")) def is_rounded_total_disabled(self): @@ -1674,14 +1722,59 @@ def get_advance_payment_entries(party_type, party, party_account, order_doctype, return list(payment_entries_against_order) + list(unallocated_payment_entries) def update_invoice_status(): - # Daily update the status of the invoices - - frappe.db.sql(""" update `tabSales Invoice` set status = 'Overdue' - where due_date < CURDATE() and docstatus = 1 and outstanding_amount > 0""") - - frappe.db.sql(""" update `tabPurchase Invoice` set status = 'Overdue' - where due_date < CURDATE() and docstatus = 1 and outstanding_amount > 0""") + """Updates status as Overdue for applicable invoices. Runs daily.""" + today = getdate() + for doctype in ("Sales Invoice", "Purchase Invoice"): + frappe.db.sql(""" + UPDATE `tab{doctype}` invoice SET invoice.status = 'Overdue' + WHERE invoice.docstatus = 1 + AND invoice.status REGEXP '^Unpaid|^Partly Paid' + AND invoice.outstanding_amount > 0 + AND ( + {or_condition} + ( + ( + CASE + WHEN invoice.party_account_currency = invoice.currency + THEN ( + CASE + WHEN invoice.disable_rounded_total + THEN invoice.grand_total + ELSE invoice.rounded_total + END + ) + ELSE ( + CASE + WHEN invoice.disable_rounded_total + THEN invoice.base_grand_total + ELSE invoice.base_rounded_total + END + ) + END + ) - invoice.outstanding_amount + ) < ( + SELECT SUM( + CASE + WHEN invoice.party_account_currency = invoice.currency + THEN ps.payment_amount + ELSE ps.base_payment_amount + END + ) + FROM `tabPayment Schedule` ps + WHERE ps.parent = invoice.name + AND ps.due_date < %(today)s + ) + ) + """.format( + doctype=doctype, + or_condition=( + "invoice.is_pos AND invoice.due_date < %(today)s OR" + if doctype == "Sales Invoice" + else "" + ) + ), {"today": today} + ) @frappe.whitelist() def get_payment_terms(terms_template, posting_date=None, grand_total=None, base_grand_total=None, bill_date=None): @@ -1701,7 +1794,7 @@ def get_payment_terms(terms_template, posting_date=None, grand_total=None, base_ @frappe.whitelist() def get_payment_term_details(term, posting_date=None, grand_total=None, base_grand_total=None, bill_date=None): term_details = frappe._dict() - if isinstance(term, text_type): + if isinstance(term, str): term = frappe.get_doc("Payment Term", term) else: term_details.payment_term = term.payment_term diff --git a/erpnext/controllers/buying_controller.py b/erpnext/controllers/buying_controller.py index e0b3ad801ec..a3d2502268e 100644 --- a/erpnext/controllers/buying_controller.py +++ b/erpnext/controllers/buying_controller.py @@ -1,10 +1,9 @@ # Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors # License: GNU General Public License v3. See license.txt -from __future__ import unicode_literals import frappe -from frappe import _, msgprint +from frappe import ValidationError, _, msgprint from frappe.contacts.doctype.address.address import get_address_display from frappe.utils import cint, cstr, flt, getdate @@ -18,6 +17,9 @@ from erpnext.stock.get_item_details import get_conversion_factor from erpnext.stock.utils import get_incoming_rate +class QtyMismatchError(ValidationError): + pass + class BuyingController(StockController, Subcontracting): def get_feed(self): @@ -361,19 +363,15 @@ class BuyingController(StockController, Subcontracting): def validate_accepted_rejected_qty(self): for d in self.get("items"): self.validate_negative_quantity(d, ["received_qty","qty", "rejected_qty"]) - if not flt(d.received_qty) and flt(d.qty): - d.received_qty = flt(d.qty) - flt(d.rejected_qty) - elif not flt(d.qty) and flt(d.rejected_qty): - d.qty = flt(d.received_qty) - flt(d.rejected_qty) + if not flt(d.received_qty) and (flt(d.qty) or flt(d.rejected_qty)): + d.received_qty = flt(d.qty) + flt(d.rejected_qty) - elif not flt(d.rejected_qty): - d.rejected_qty = flt(d.received_qty) - flt(d.qty) - - val = flt(d.qty) + flt(d.rejected_qty) # Check Received Qty = Accepted Qty + Rejected Qty + val = flt(d.qty) + flt(d.rejected_qty) if (flt(val, d.precision("received_qty")) != flt(d.received_qty, d.precision("received_qty"))): - frappe.throw(_("Accepted + Rejected Qty must be equal to Received quantity for Item {0}").format(d.item_code)) + message = _("Row #{0}: Received Qty must be equal to Accepted + Rejected Qty for Item {1}").format(d.idx, d.item_code) + frappe.throw(msg=message, title=_("Mismatch"), exc=QtyMismatchError) def validate_negative_quantity(self, item_row, field_list): if self.is_return: diff --git a/erpnext/controllers/item_variant.py b/erpnext/controllers/item_variant.py index 1b56ae9d4dc..2bad6f8e9f4 100644 --- a/erpnext/controllers/item_variant.py +++ b/erpnext/controllers/item_variant.py @@ -1,7 +1,6 @@ # Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors # License: GNU General Public License v3. See license.txt -from __future__ import unicode_literals import copy import json @@ -9,7 +8,6 @@ import json import frappe from frappe import _ from frappe.utils import cstr, flt -from six import string_types class ItemVariantExistsError(frappe.ValidationError): pass @@ -31,7 +29,7 @@ def get_variant(template, args=None, variant=None, manufacturer=None, return make_variant_based_on_manufacturer(item_template, manufacturer, manufacturer_part_no) else: - if isinstance(args, string_types): + if isinstance(args, str): args = json.loads(args) if not args: @@ -55,7 +53,7 @@ def make_variant_based_on_manufacturer(template, manufacturer, manufacturer_part return variant def validate_item_variant_attributes(item, args=None): - if isinstance(item, string_types): + if isinstance(item, str): item = frappe.get_doc('Item', item) if not args: @@ -157,7 +155,7 @@ def find_variant(template, args, variant_item_code=None): @frappe.whitelist() def create_variant(item, args): - if isinstance(args, string_types): + if isinstance(args, str): args = json.loads(args) template = frappe.get_doc("Item", item) @@ -180,7 +178,7 @@ def create_variant(item, args): @frappe.whitelist() def enqueue_multiple_variant_creation(item, args): # There can be innumerable attribute combinations, enqueue - if isinstance(args, string_types): + if isinstance(args, str): variants = json.loads(args) total_variants = 1 for key in variants: @@ -197,7 +195,7 @@ def enqueue_multiple_variant_creation(item, args): def create_multiple_variants(item, args): count = 0 - if isinstance(args, string_types): + if isinstance(args, str): args = json.loads(args) args_set = generate_keyed_value_combinations(args) diff --git a/erpnext/controllers/print_settings.py b/erpnext/controllers/print_settings.py index f6e061bcdcf..cf9de52d4cd 100644 --- a/erpnext/controllers/print_settings.py +++ b/erpnext/controllers/print_settings.py @@ -1,7 +1,6 @@ # Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors # License: GNU General Public License v3. See license.txt -from __future__ import unicode_literals def set_print_templates_for_item_table(doc, settings): diff --git a/erpnext/controllers/queries.py b/erpnext/controllers/queries.py index aafaf5b9e08..76a7d1a95ff 100644 --- a/erpnext/controllers/queries.py +++ b/erpnext/controllers/queries.py @@ -1,12 +1,12 @@ # Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors # License: GNU General Public License v3. See license.txt -from __future__ import unicode_literals import json from collections import defaultdict import frappe +from frappe import scrub from frappe.desk.reportview import get_filters_cond, get_match_cond from frappe.utils import nowdate, unique @@ -131,7 +131,8 @@ def supplier_query(doctype, txt, searchfield, start, page_len, filters): return frappe.db.sql("""select {field} from `tabSupplier` where docstatus < 2 and ({key} like %(txt)s - or supplier_name like %(txt)s) and disabled=0 + or supplier_name like %(txt)s) and disabled=0 + and (on_hold = 0 or (on_hold = 1 and CURDATE() > release_date)) {mcond} order by if(locate(%(_txt)s, name), locate(%(_txt)s, name), 99999), @@ -209,12 +210,15 @@ def item_query(doctype, txt, searchfield, start, page_len, filters, as_dict=Fals meta = frappe.get_meta("Item", cached=True) searchfields = meta.get_search_fields() - if "description" in searchfields: - searchfields.remove("description") + # these are handled separately + ignored_search_fields = ("item_name", "description") + for ignored_field in ignored_search_fields: + if ignored_field in searchfields: + searchfields.remove(ignored_field) columns = '' extra_searchfields = [field for field in searchfields - if not field in ["name", "item_group", "description"]] + if not field in ["name", "item_group", "description", "item_name"]] if extra_searchfields: columns = ", " + ", ".join(extra_searchfields) @@ -223,27 +227,36 @@ def item_query(doctype, txt, searchfield, start, page_len, filters, as_dict=Fals if not field in searchfields] searchfields = " or ".join([field + " like %(txt)s" for field in searchfields]) - if filters and isinstance(filters, dict) and filters.get('supplier'): - item_group_list = frappe.get_all('Supplier Item Group', - filters = {'supplier': filters.get('supplier')}, fields = ['item_group']) + if filters and isinstance(filters, dict): + if filters.get('customer') or filters.get('supplier'): + party = filters.get('customer') or filters.get('supplier') + item_rules_list = frappe.get_all('Party Specific Item', + filters = {'party': party}, fields = ['restrict_based_on', 'based_on_value']) - item_groups = [] - for i in item_group_list: - item_groups.append(i.item_group) + filters_dict = {} + for rule in item_rules_list: + if rule['restrict_based_on'] == 'Item': + rule['restrict_based_on'] = 'name' + filters_dict[rule.restrict_based_on] = [] - del filters['supplier'] + for rule in item_rules_list: + filters_dict[rule.restrict_based_on].append(rule.based_on_value) + + for filter in filters_dict: + filters[scrub(filter)] = ['in', filters_dict[filter]] + + if filters.get('customer'): + del filters['customer'] + else: + del filters['supplier'] - if item_groups: - filters['item_group'] = ['in', item_groups] description_cond = '' if frappe.db.count('Item', cache=True) < 50000: # scan description only if items are less than 50000 description_cond = 'or tabItem.description LIKE %(txt)s' - return frappe.db.sql("""select tabItem.name, - if(length(tabItem.item_name) > 40, - concat(substr(tabItem.item_name, 1, 40), "..."), item_name) as item_name, - tabItem.item_group, + return frappe.db.sql("""select + tabItem.name, tabItem.item_name, tabItem.item_group, if(length(tabItem.description) > 40, \ concat(substr(tabItem.description, 1, 40), "..."), description) as description {columns} @@ -307,7 +320,7 @@ def bom(doctype, txt, searchfield, start, page_len, filters): @frappe.validate_and_sanitize_search_inputs def get_project_name(doctype, txt, searchfield, start, page_len, filters): cond = '' - if filters.get('customer'): + if filters and filters.get('customer'): cond = """(`tabProject`.customer = %s or ifnull(`tabProject`.customer,"")="") and""" %(frappe.db.escape(filters.get("customer"))) @@ -553,7 +566,7 @@ def get_filtered_dimensions(doctype, txt, searchfield, start, page_len, filters) query_filters.append(['name', query_selector, dimensions]) - output = frappe.get_all(doctype, filters=query_filters) + output = frappe.get_list(doctype, filters=query_filters) result = [d.name for d in output] return [(d,) for d in set(result)] @@ -684,36 +697,6 @@ def get_purchase_invoices(doctype, txt, searchfield, start, page_len, filters): return frappe.db.sql(query, filters) -@frappe.whitelist() -@frappe.validate_and_sanitize_search_inputs -def get_healthcare_service_units(doctype, txt, searchfield, start, page_len, filters): - query = """ - select name - from `tabHealthcare Service Unit` - where - is_group = 0 - and company = {company} - and name like {txt}""".format( - company = frappe.db.escape(filters.get('company')), txt = frappe.db.escape('%{0}%'.format(txt))) - - if filters and filters.get('inpatient_record'): - from erpnext.healthcare.doctype.inpatient_medication_entry.inpatient_medication_entry import ( - get_current_healthcare_service_unit, - ) - service_unit = get_current_healthcare_service_unit(filters.get('inpatient_record')) - - # if the patient is admitted, then appointments should be allowed against the admission service unit, - # inspite of it being an Inpatient Occupancy service unit - if service_unit: - query += " and (allow_appointments = 1 or name = {service_unit})".format(service_unit = frappe.db.escape(service_unit)) - else: - query += " and allow_appointments = 1" - else: - query += " and allow_appointments = 1" - - return frappe.db.sql(query, filters) - - @frappe.whitelist() @frappe.validate_and_sanitize_search_inputs def get_tax_template(doctype, txt, searchfield, start, page_len, filters): diff --git a/erpnext/controllers/sales_and_purchase_return.py b/erpnext/controllers/sales_and_purchase_return.py index 5f2fbeb0c93..df3c5f10c1b 100644 --- a/erpnext/controllers/sales_and_purchase_return.py +++ b/erpnext/controllers/sales_and_purchase_return.py @@ -1,7 +1,6 @@ # Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors # License: GNU General Public License v3. See license.txt -from __future__ import unicode_literals import frappe from frappe import _ diff --git a/erpnext/controllers/selling_controller.py b/erpnext/controllers/selling_controller.py index 0158a1120f9..dad3ed70933 100644 --- a/erpnext/controllers/selling_controller.py +++ b/erpnext/controllers/selling_controller.py @@ -1,7 +1,6 @@ # Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors # License: GNU General Public License v3. See license.txt -from __future__ import unicode_literals import frappe from frappe import _, bold, throw @@ -424,7 +423,7 @@ class SellingController(StockController): or (cint(self.is_return) and self.docstatus==2)): sl_entries.append(self.get_sle_for_source_warehouse(d)) - if d.target_warehouse and self.get("is_internal_customer"): + if d.target_warehouse: sl_entries.append(self.get_sle_for_target_warehouse(d)) if d.warehouse and ((not cint(self.is_return) and self.docstatus==2) @@ -559,6 +558,12 @@ class SellingController(StockController): frappe.throw(_("Row {0}: Delivery Warehouse ({1}) and Customer Warehouse ({2}) can not be same") .format(d.idx, warehouse, warehouse)) + if not self.get("is_internal_customer") and any(d.get("target_warehouse") for d in items): + msg = _("Target Warehouse is set for some items but the customer is not an internal customer.") + msg += " " + _("This {} will be treated as material transfer.").format(_(self.doctype)) + frappe.msgprint(msg, title="Internal Transfer", alert=True) + + def validate_items(self): # validate items to see if they have is_sales_item enabled from erpnext.controllers.buying_controller import validate_item_type diff --git a/erpnext/controllers/status_updater.py b/erpnext/controllers/status_updater.py index 8738204ce09..76a7cdab516 100644 --- a/erpnext/controllers/status_updater.py +++ b/erpnext/controllers/status_updater.py @@ -1,7 +1,6 @@ # Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors # License: GNU General Public License v3. See license.txt -from __future__ import unicode_literals import frappe from frappe import _ @@ -216,11 +215,14 @@ class StatusUpdater(Document): overflow_percent = ((item[args['target_field']] - item[args['target_ref_field']]) / item[args['target_ref_field']]) * 100 - if overflow_percent - allowance > 0.01 and role not in frappe.get_roles(): + if overflow_percent - allowance > 0.01: item['max_allowed'] = flt(item[args['target_ref_field']] * (100+allowance)/100) item['reduce_by'] = item[args['target_field']] - item['max_allowed'] - self.limits_crossed_error(args, item, qty_or_amount) + if role not in frappe.get_roles(): + self.limits_crossed_error(args, item, qty_or_amount) + else: + self.warn_about_bypassing_with_role(item, qty_or_amount, role) def limits_crossed_error(self, args, item, qty_or_amount): '''Raise exception for limits crossed''' @@ -238,6 +240,19 @@ class StatusUpdater(Document): frappe.bold(item.get('item_code')) ) + '

' + action_msg, OverAllowanceError, title = _('Limit Crossed')) + def warn_about_bypassing_with_role(self, item, qty_or_amount, role): + action = _("Over Receipt/Delivery") if qty_or_amount == "qty" else _("Overbilling") + + msg = (_("{} of {} {} ignored for item {} because you have {} role.") + .format( + action, + _(item["target_ref_field"].title()), + frappe.bold(item["reduce_by"]), + frappe.bold(item.get('item_code')), + role) + ) + frappe.msgprint(msg, indicator="orange", alert=True) + def update_qty(self, update_modified=True): """Updates qty or amount at row level diff --git a/erpnext/controllers/stock_controller.py b/erpnext/controllers/stock_controller.py index 78a6e52e4d7..aba15b47e3a 100644 --- a/erpnext/controllers/stock_controller.py +++ b/erpnext/controllers/stock_controller.py @@ -79,8 +79,15 @@ class StockController(AccountsController): def clean_serial_nos(self): for row in self.get("items"): if hasattr(row, "serial_no") and row.serial_no: - # replace commas by linefeed and remove all spaces in string - row.serial_no = row.serial_no.replace(",", "\n").replace(" ", "") + # replace commas by linefeed + row.serial_no = row.serial_no.replace(",", "\n") + + # strip preceeding and succeeding spaces for each SN + # (SN could have valid spaces in between e.g. SN - 123 - 2021) + serial_no_list = row.serial_no.split("\n") + serial_no_list = [sn.strip() for sn in serial_no_list] + + row.serial_no = "\n".join(serial_no_list) def get_gl_entries(self, warehouse_account=None, default_expense_account=None, default_cost_center=None): @@ -591,7 +598,7 @@ def future_sle_exists(args, sl_entries=None): data = frappe.db.sql(""" select item_code, warehouse, count(name) as total_row - from `tabStock Ledger Entry` + from `tabStock Ledger Entry` force index (item_warehouse) where ({}) and timestamp(posting_date, posting_time) @@ -669,5 +676,6 @@ def create_repost_item_valuation_entry(args): repost_entry.company = args.company repost_entry.allow_zero_rate = args.allow_zero_rate repost_entry.flags.ignore_links = True + repost_entry.flags.ignore_permissions = True repost_entry.save() repost_entry.submit() diff --git a/erpnext/controllers/taxes_and_totals.py b/erpnext/controllers/taxes_and_totals.py index 70cc8a58bfe..746c6fd9a42 100644 --- a/erpnext/controllers/taxes_and_totals.py +++ b/erpnext/controllers/taxes_and_totals.py @@ -1,7 +1,6 @@ # Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors # License: GNU General Public License v3. See license.txt -from __future__ import unicode_literals import json @@ -51,6 +50,7 @@ class calculate_taxes_and_totals(object): self.initialize_taxes() self.determine_exclusive_rate() self.calculate_net_total() + self.calculate_shipping_charges() self.calculate_taxes() self.manipulate_grand_total_for_inclusive_tax() self.calculate_totals() @@ -177,7 +177,7 @@ class calculate_taxes_and_totals(object): self.doc.round_floats_in(tax) def determine_exclusive_rate(self): - if not any((cint(tax.included_in_print_rate) for tax in self.doc.get("taxes"))): + if not any(cint(tax.included_in_print_rate) for tax in self.doc.get("taxes")): return for item in self.doc.get("items"): @@ -259,8 +259,15 @@ class calculate_taxes_and_totals(object): self.doc.round_floats_in(self.doc, ["total", "base_total", "net_total", "base_net_total"]) + def calculate_shipping_charges(self): + if hasattr(self.doc, "shipping_rule") and self.doc.shipping_rule: + shipping_rule = frappe.get_doc("Shipping Rule", self.doc.shipping_rule) + shipping_rule.apply(self.doc) + def calculate_taxes(self): - self.doc.rounding_adjustment = 0 + if not self.doc.get('is_consolidated'): + self.doc.rounding_adjustment = 0 + # maintain actual tax rate based on idx actual_tax_dict = dict([[tax.idx, flt(tax.tax_amount, tax.precision("tax_amount"))] for tax in self.doc.get("taxes") if tax.charge_type == "Actual"]) @@ -312,7 +319,9 @@ class calculate_taxes_and_totals(object): # adjust Discount Amount loss in last tax iteration if i == (len(self.doc.get("taxes")) - 1) and self.discount_amount_applied \ - and self.doc.discount_amount and self.doc.apply_discount_on == "Grand Total": + and self.doc.discount_amount \ + and self.doc.apply_discount_on == "Grand Total" \ + and not self.doc.get('is_consolidated'): self.doc.rounding_adjustment = flt(self.doc.grand_total - flt(self.doc.discount_amount) - tax.total, self.doc.precision("rounding_adjustment")) @@ -405,11 +414,16 @@ class calculate_taxes_and_totals(object): self.doc.rounding_adjustment = diff def calculate_totals(self): - self.doc.grand_total = flt(self.doc.get("taxes")[-1].total) + flt(self.doc.rounding_adjustment) \ - if self.doc.get("taxes") else flt(self.doc.net_total) + if self.doc.get("taxes"): + self.doc.grand_total = flt(self.doc.get("taxes")[-1].total) + flt(self.doc.rounding_adjustment) + else: + self.doc.grand_total = flt(self.doc.net_total) - self.doc.total_taxes_and_charges = flt(self.doc.grand_total - self.doc.net_total + if self.doc.get("taxes"): + self.doc.total_taxes_and_charges = flt(self.doc.grand_total - self.doc.net_total - flt(self.doc.rounding_adjustment), self.doc.precision("total_taxes_and_charges")) + else: + self.doc.total_taxes_and_charges = 0.0 self._set_in_company_currency(self.doc, ["total_taxes_and_charges", "rounding_adjustment"]) @@ -446,19 +460,20 @@ class calculate_taxes_and_totals(object): self.doc.total_net_weight += d.total_weight def set_rounded_total(self): - if self.doc.meta.get_field("rounded_total"): - if self.doc.is_rounded_total_disabled(): - self.doc.rounded_total = self.doc.base_rounded_total = 0 - return + if not self.doc.get('is_consolidated'): + if self.doc.meta.get_field("rounded_total"): + if self.doc.is_rounded_total_disabled(): + self.doc.rounded_total = self.doc.base_rounded_total = 0 + return - self.doc.rounded_total = round_based_on_smallest_currency_fraction(self.doc.grand_total, - self.doc.currency, self.doc.precision("rounded_total")) + self.doc.rounded_total = round_based_on_smallest_currency_fraction(self.doc.grand_total, + self.doc.currency, self.doc.precision("rounded_total")) - #if print_in_rate is set, we would have already calculated rounding adjustment - self.doc.rounding_adjustment += flt(self.doc.rounded_total - self.doc.grand_total, - self.doc.precision("rounding_adjustment")) + #if print_in_rate is set, we would have already calculated rounding adjustment + self.doc.rounding_adjustment += flt(self.doc.rounded_total - self.doc.grand_total, + self.doc.precision("rounding_adjustment")) - self._set_in_company_currency(self.doc, ["rounding_adjustment", "rounded_total"]) + self._set_in_company_currency(self.doc, ["rounding_adjustment", "rounded_total"]) def _cleanup(self): if not self.doc.get('is_consolidated'): diff --git a/erpnext/controllers/tests/test_item_variant.py b/erpnext/controllers/tests/test_item_variant.py index b3633e6ff09..5c6e06a7d73 100644 --- a/erpnext/controllers/tests/test_item_variant.py +++ b/erpnext/controllers/tests/test_item_variant.py @@ -1,10 +1,7 @@ -from __future__ import unicode_literals - import json import unittest import frappe -from six import string_types from erpnext.controllers.item_variant import copy_attributes_to_variant, make_variant_item_code from erpnext.stock.doctype.item.test_item import set_item_variant_settings @@ -21,7 +18,7 @@ class TestItemVariant(unittest.TestCase): self.assertEqual(variant.get("quality_inspection_template"), "_Test QC Template") def create_variant_with_tables(item, args): - if isinstance(args, string_types): + if isinstance(args, str): args = json.loads(args) qc_name = make_quality_inspection_template() diff --git a/erpnext/controllers/tests/test_mapper.py b/erpnext/controllers/tests/test_mapper.py index 2d1ae43f074..e75587607ec 100644 --- a/erpnext/controllers/tests/test_mapper.py +++ b/erpnext/controllers/tests/test_mapper.py @@ -1,5 +1,3 @@ -from __future__ import unicode_literals - import json import unittest diff --git a/erpnext/controllers/tests/test_qty_based_taxes.py b/erpnext/controllers/tests/test_qty_based_taxes.py index 41673d1e6fb..49b844bf7e8 100644 --- a/erpnext/controllers/tests/test_qty_based_taxes.py +++ b/erpnext/controllers/tests/test_qty_based_taxes.py @@ -1,5 +1,3 @@ -from __future__ import print_function, unicode_literals - import unittest from uuid import uuid4 as _uuid4 diff --git a/erpnext/controllers/tests/test_queries.py b/erpnext/controllers/tests/test_queries.py new file mode 100644 index 00000000000..05541d16887 --- /dev/null +++ b/erpnext/controllers/tests/test_queries.py @@ -0,0 +1,87 @@ +import unittest +from functools import partial + +from erpnext.controllers import queries + + +def add_default_params(func, doctype): + return partial( + func, doctype=doctype, txt="", searchfield="name", start=0, page_len=20, filters=None + ) + + +class TestQueries(unittest.TestCase): + + # All tests are based on doctype/test_records.json + + def assert_nested_in(self, item, container): + self.assertIn(item, [vals for tuples in container for vals in tuples]) + + def test_employee_query(self): + query = add_default_params(queries.employee_query, "Employee") + + self.assertGreaterEqual(len(query(txt="_Test Employee")), 3) + self.assertGreaterEqual(len(query(txt="_Test Employee 1")), 1) + + def test_lead_query(self): + query = add_default_params(queries.lead_query, "Lead") + + self.assertGreaterEqual(len(query(txt="_Test Lead")), 4) + self.assertEqual(len(query(txt="_Test Lead 4")), 1) + + def test_customer_query(self): + query = add_default_params(queries.customer_query, "Customer") + + self.assertGreaterEqual(len(query(txt="_Test Customer")), 7) + self.assertGreaterEqual(len(query(txt="_Test Customer USD")), 1) + + def test_supplier_query(self): + query = add_default_params(queries.supplier_query, "Supplier") + + self.assertGreaterEqual(len(query(txt="_Test Supplier")), 7) + self.assertGreaterEqual(len(query(txt="_Test Supplier USD")), 1) + + def test_item_query(self): + query = add_default_params(queries.item_query, "Item") + + self.assertGreaterEqual(len(query(txt="_Test Item")), 7) + self.assertEqual(len(query(txt="_Test Item Home Desktop 100 3")), 1) + + fg_item = "_Test FG Item" + stock_items = query(txt=fg_item, filters={"is_stock_item": 1}) + self.assert_nested_in("_Test FG Item", stock_items) + + bundled_stock_items = query(txt="_test product bundle item 5", filters={"is_stock_item": 1}) + self.assertEqual(len(bundled_stock_items), 0) + + def test_bom_qury(self): + query = add_default_params(queries.bom, "BOM") + + self.assertGreaterEqual(len(query(txt="_Test Item Home Desktop Manufactured")), 1) + + def test_project_query(self): + query = add_default_params(queries.get_project_name, "BOM") + + self.assertGreaterEqual(len(query(txt="_Test Project")), 1) + + def test_account_query(self): + query = add_default_params(queries.get_account_list, "Account") + + debtor_accounts = query(txt="Debtors", filters={"company": "_Test Company"}) + self.assert_nested_in("Debtors - _TC", debtor_accounts) + + def test_income_account_query(self): + query = add_default_params(queries.get_income_account, "Account") + + self.assertGreaterEqual(len(query(filters={"company": "_Test Company"})), 1) + + def test_expense_account_query(self): + query = add_default_params(queries.get_expense_account, "Account") + + self.assertGreaterEqual(len(query(filters={"company": "_Test Company"})), 1) + + def test_warehouse_query(self): + query = add_default_params(queries.warehouse_query, "Account") + + wh = query(filters=[["Bin", "item_code", "=", "_Test Item"]]) + self.assertGreaterEqual(len(wh), 1) diff --git a/erpnext/controllers/trends.py b/erpnext/controllers/trends.py index 05d900d0f04..1cb101f214a 100644 --- a/erpnext/controllers/trends.py +++ b/erpnext/controllers/trends.py @@ -1,7 +1,6 @@ # Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors # License: GNU General Public License v3. See license.txt -from __future__ import unicode_literals import frappe from frappe import _ diff --git a/erpnext/controllers/website_list_for_contact.py b/erpnext/controllers/website_list_for_contact.py index ff2ed45bd24..23463abe0ae 100644 --- a/erpnext/controllers/website_list_for_contact.py +++ b/erpnext/controllers/website_list_for_contact.py @@ -1,12 +1,12 @@ # Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors # License: GNU General Public License v3. See license.txt -from __future__ import unicode_literals import json import frappe from frappe import _ +from frappe.modules.utils import get_module_app from frappe.utils import flt, has_common from frappe.utils.user import is_website_user @@ -21,8 +21,32 @@ def get_list_context(context=None): "get_list": get_transaction_list } +def get_webform_list_context(module): + if get_module_app(module) != 'erpnext': + return + return { + "get_list": get_webform_transaction_list + } -def get_transaction_list(doctype, txt=None, filters=None, limit_start=0, limit_page_length=20, order_by="modified"): +def get_webform_transaction_list(doctype, txt=None, filters=None, limit_start=0, limit_page_length=20, order_by="modified"): + """ Get List of transactions for custom doctypes """ + from frappe.www.list import get_list + + if not filters: + filters = [] + + meta = frappe.get_meta(doctype) + + for d in meta.fields: + if d.fieldtype == 'Link' and d.fieldname != 'amended_from': + allowed_docs = [d.name for d in get_transaction_list(doctype=d.options, custom=True)] + allowed_docs.append('') + filters.append((d.fieldname, 'in', allowed_docs)) + + return get_list(doctype, txt, filters, limit_start, limit_page_length, ignore_permissions=False, + fields=None, order_by="modified") + +def get_transaction_list(doctype, txt=None, filters=None, limit_start=0, limit_page_length=20, order_by="modified", custom=False): user = frappe.session.user ignore_permissions = False @@ -46,7 +70,7 @@ def get_transaction_list(doctype, txt=None, filters=None, limit_start=0, limit_p filters.append(('customer', 'in', customers)) elif suppliers: filters.append(('supplier', 'in', suppliers)) - else: + elif not custom: return [] if doctype == 'Request for Quotation': @@ -56,9 +80,16 @@ def get_transaction_list(doctype, txt=None, filters=None, limit_start=0, limit_p # Since customers and supplier do not have direct access to internal doctypes ignore_permissions = True + if not customers and not suppliers and custom: + ignore_permissions = False + filters = [] + transactions = get_list_for_transactions(doctype, txt, filters, limit_start, limit_page_length, fields='name', ignore_permissions=ignore_permissions, order_by='modified desc') + if custom: + return transactions + return post_process(doctype, transactions) def get_list_for_transactions(doctype, txt, filters, limit_start, limit_page_length=20, diff --git a/erpnext/crm/doctype/appointment/appointment.py b/erpnext/crm/doctype/appointment/appointment.py index f2055349bd2..20fb987c601 100644 --- a/erpnext/crm/doctype/appointment/appointment.py +++ b/erpnext/crm/doctype/appointment/appointment.py @@ -1,8 +1,6 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2019, Frappe Technologies Pvt. Ltd. and contributors # For license information, please see license.txt -from __future__ import unicode_literals from collections import Counter diff --git a/erpnext/crm/doctype/appointment/test_appointment.py b/erpnext/crm/doctype/appointment/test_appointment.py index 59138a9ea9b..f4086dc37c8 100644 --- a/erpnext/crm/doctype/appointment/test_appointment.py +++ b/erpnext/crm/doctype/appointment/test_appointment.py @@ -1,7 +1,5 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2019, Frappe Technologies Pvt. Ltd. and Contributors # See license.txt -from __future__ import unicode_literals import datetime import unittest diff --git a/erpnext/crm/doctype/appointment_booking_settings/appointment_booking_settings.py b/erpnext/crm/doctype/appointment_booking_settings/appointment_booking_settings.py index 7e1da677312..1431b03a2ef 100644 --- a/erpnext/crm/doctype/appointment_booking_settings/appointment_booking_settings.py +++ b/erpnext/crm/doctype/appointment_booking_settings/appointment_booking_settings.py @@ -1,8 +1,6 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2019, Frappe Technologies Pvt. Ltd. and contributors # For license information, please see license.txt -from __future__ import unicode_literals import datetime diff --git a/erpnext/crm/doctype/appointment_booking_settings/test_appointment_booking_settings.py b/erpnext/crm/doctype/appointment_booking_settings/test_appointment_booking_settings.py index 5c5432c5246..bc68bbd86c6 100644 --- a/erpnext/crm/doctype/appointment_booking_settings/test_appointment_booking_settings.py +++ b/erpnext/crm/doctype/appointment_booking_settings/test_appointment_booking_settings.py @@ -1,7 +1,5 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2019, Frappe Technologies Pvt. Ltd. and Contributors # See license.txt -from __future__ import unicode_literals # import frappe import unittest diff --git a/erpnext/crm/doctype/appointment_booking_slots/appointment_booking_slots.py b/erpnext/crm/doctype/appointment_booking_slots/appointment_booking_slots.py index 4741c8af5a1..756c8495e0a 100644 --- a/erpnext/crm/doctype/appointment_booking_slots/appointment_booking_slots.py +++ b/erpnext/crm/doctype/appointment_booking_slots/appointment_booking_slots.py @@ -1,8 +1,6 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2019, Frappe Technologies Pvt. Ltd. and contributors # For license information, please see license.txt -from __future__ import unicode_literals # import frappe from frappe.model.document import Document diff --git a/erpnext/crm/doctype/availability_of_slots/availability_of_slots.py b/erpnext/crm/doctype/availability_of_slots/availability_of_slots.py index e33d87b1939..4294e6da2d2 100644 --- a/erpnext/crm/doctype/availability_of_slots/availability_of_slots.py +++ b/erpnext/crm/doctype/availability_of_slots/availability_of_slots.py @@ -1,8 +1,6 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2019, Frappe Technologies Pvt. Ltd. and contributors # For license information, please see license.txt -from __future__ import unicode_literals # import frappe from frappe.model.document import Document diff --git a/erpnext/crm/doctype/campaign_email_schedule/campaign_email_schedule.py b/erpnext/crm/doctype/campaign_email_schedule/campaign_email_schedule.py index f053e6e7e4f..de9b5a1192c 100644 --- a/erpnext/crm/doctype/campaign_email_schedule/campaign_email_schedule.py +++ b/erpnext/crm/doctype/campaign_email_schedule/campaign_email_schedule.py @@ -1,8 +1,6 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2019, Frappe Technologies Pvt. Ltd. and contributors # For license information, please see license.txt -from __future__ import unicode_literals # import frappe from frappe.model.document import Document diff --git a/erpnext/healthcare/doctype/appointment_type/__init__.py b/erpnext/crm/doctype/competitor/__init__.py similarity index 100% rename from erpnext/healthcare/doctype/appointment_type/__init__.py rename to erpnext/crm/doctype/competitor/__init__.py diff --git a/erpnext/buying/doctype/supplier_item_group/supplier_item_group.js b/erpnext/crm/doctype/competitor/competitor.js similarity index 79% rename from erpnext/buying/doctype/supplier_item_group/supplier_item_group.js rename to erpnext/crm/doctype/competitor/competitor.js index f7da90d98d6..a5b617dc74c 100644 --- a/erpnext/buying/doctype/supplier_item_group/supplier_item_group.js +++ b/erpnext/crm/doctype/competitor/competitor.js @@ -1,7 +1,7 @@ // Copyright (c) 2021, Frappe Technologies Pvt. Ltd. and contributors // For license information, please see license.txt -frappe.ui.form.on('Supplier Item Group', { +frappe.ui.form.on('Competitor', { // refresh: function(frm) { // } diff --git a/erpnext/healthcare/doctype/lab_test_sample/lab_test_sample.json b/erpnext/crm/doctype/competitor/competitor.json similarity index 51% rename from erpnext/healthcare/doctype/lab_test_sample/lab_test_sample.json rename to erpnext/crm/doctype/competitor/competitor.json index 2830038eafd..280441f16fd 100644 --- a/erpnext/healthcare/doctype/lab_test_sample/lab_test_sample.json +++ b/erpnext/crm/doctype/competitor/competitor.json @@ -1,43 +1,54 @@ { "actions": [], - "allow_copy": 1, - "allow_import": 1, "allow_rename": 1, - "autoname": "field:sample", - "beta": 1, - "creation": "2016-04-04 17:35:44.823951", + "autoname": "field:competitor_name", + "creation": "2021-10-21 10:28:52.071316", "doctype": "DocType", - "document_type": "Setup", + "editable_grid": 1, "engine": "InnoDB", "field_order": [ - "sample", - "sample_uom" + "competitor_name", + "website" ], "fields": [ { - "fieldname": "sample", + "fieldname": "competitor_name", "fieldtype": "Data", "in_list_view": 1, - "label": "Sample", + "label": "Competitor Name", "reqd": 1, "unique": 1 }, { - "bold": 1, - "fieldname": "sample_uom", - "fieldtype": "Link", + "allow_in_quick_entry": 1, + "fieldname": "website", + "fieldtype": "Data", "in_list_view": 1, - "label": "UOM", - "options": "Lab Test UOM" + "label": "Website", + "options": "URL" } ], + "index_web_pages_for_search": 1, "links": [], - "modified": "2020-01-29 23:02:02.249839", + "modified": "2021-10-21 12:43:59.106807", "modified_by": "Administrator", - "module": "Healthcare", - "name": "Lab Test Sample", + "module": "CRM", + "name": "Competitor", + "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, "email": 1, @@ -45,24 +56,13 @@ "print": 1, "read": 1, "report": 1, - "role": "Healthcare Administrator", + "role": "Sales User", "share": 1, "write": 1 - }, - { - "email": 1, - "export": 1, - "print": 1, - "read": 1, - "report": 1, - "role": "Laboratory User", - "share": 1 } ], "quick_entry": 1, - "restrict_to_domain": "Healthcare", "sort_field": "modified", "sort_order": "DESC", - "title_field": "sample", "track_changes": 1 } \ No newline at end of file diff --git a/erpnext/healthcare/doctype/treatment_plan_template_item/treatment_plan_template_item.py b/erpnext/crm/doctype/competitor/competitor.py similarity index 81% rename from erpnext/healthcare/doctype/treatment_plan_template_item/treatment_plan_template_item.py rename to erpnext/crm/doctype/competitor/competitor.py index 8b8d89f07f3..a292e461048 100644 --- a/erpnext/healthcare/doctype/treatment_plan_template_item/treatment_plan_template_item.py +++ b/erpnext/crm/doctype/competitor/competitor.py @@ -5,5 +5,5 @@ from frappe.model.document import Document -class TreatmentPlanTemplateItem(Document): +class Competitor(Document): pass diff --git a/erpnext/healthcare/doctype/treatment_plan_template/test_treatment_plan_template.py b/erpnext/crm/doctype/competitor/test_competitor.py similarity index 71% rename from erpnext/healthcare/doctype/treatment_plan_template/test_treatment_plan_template.py rename to erpnext/crm/doctype/competitor/test_competitor.py index b8a1dd77869..f77d7e658dc 100644 --- a/erpnext/healthcare/doctype/treatment_plan_template/test_treatment_plan_template.py +++ b/erpnext/crm/doctype/competitor/test_competitor.py @@ -5,5 +5,5 @@ import unittest -class TestTreatmentPlanTemplate(unittest.TestCase): +class TestCompetitor(unittest.TestCase): pass diff --git a/erpnext/healthcare/doctype/appointment_type_service_item/__init__.py b/erpnext/crm/doctype/competitor_detail/__init__.py similarity index 100% rename from erpnext/healthcare/doctype/appointment_type_service_item/__init__.py rename to erpnext/crm/doctype/competitor_detail/__init__.py diff --git a/erpnext/healthcare/doctype/treatment_plan_template_practitioner/treatment_plan_template_practitioner.json b/erpnext/crm/doctype/competitor_detail/competitor_detail.json similarity index 59% rename from erpnext/healthcare/doctype/treatment_plan_template_practitioner/treatment_plan_template_practitioner.json rename to erpnext/crm/doctype/competitor_detail/competitor_detail.json index 04da387f7b8..9512b22a3f2 100644 --- a/erpnext/healthcare/doctype/treatment_plan_template_practitioner/treatment_plan_template_practitioner.json +++ b/erpnext/crm/doctype/competitor_detail/competitor_detail.json @@ -1,29 +1,30 @@ { "actions": [], - "creation": "2021-06-10 10:37:56.669416", + "allow_rename": 1, + "creation": "2021-10-21 10:34:58.841689", "doctype": "DocType", "editable_grid": 1, "engine": "InnoDB", "field_order": [ - "practitioner" + "competitor" ], "fields": [ { - "fieldname": "practitioner", + "fieldname": "competitor", "fieldtype": "Link", "in_list_view": 1, - "label": "Practitioner", - "options": "Healthcare Practitioner", + "label": "Competitor", + "options": "Competitor", "reqd": 1 } ], "index_web_pages_for_search": 1, "istable": 1, "links": [], - "modified": "2021-06-11 16:05:06.733299", + "modified": "2021-10-21 10:34:58.841689", "modified_by": "Administrator", - "module": "Healthcare", - "name": "Treatment Plan Template Practitioner", + "module": "CRM", + "name": "Competitor Detail", "owner": "Administrator", "permissions": [], "sort_field": "modified", diff --git a/erpnext/healthcare/doctype/treatment_plan_template_practitioner/treatment_plan_template_practitioner.py b/erpnext/crm/doctype/competitor_detail/competitor_detail.py similarity index 78% rename from erpnext/healthcare/doctype/treatment_plan_template_practitioner/treatment_plan_template_practitioner.py rename to erpnext/crm/doctype/competitor_detail/competitor_detail.py index c2d08bcc1ab..0ef75605b76 100644 --- a/erpnext/healthcare/doctype/treatment_plan_template_practitioner/treatment_plan_template_practitioner.py +++ b/erpnext/crm/doctype/competitor_detail/competitor_detail.py @@ -5,5 +5,5 @@ from frappe.model.document import Document -class TreatmentPlanTemplatePractitioner(Document): +class CompetitorDetail(Document): pass diff --git a/erpnext/crm/doctype/contract/contract.py b/erpnext/crm/doctype/contract/contract.py index 9654613f041..e21f46a3837 100644 --- a/erpnext/crm/doctype/contract/contract.py +++ b/erpnext/crm/doctype/contract/contract.py @@ -1,8 +1,6 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2018, Frappe Technologies Pvt. Ltd. and contributors # For license information, please see license.txt -from __future__ import unicode_literals import frappe from frappe import _ diff --git a/erpnext/crm/doctype/contract/test_contract.py b/erpnext/crm/doctype/contract/test_contract.py index 87716368177..e685362a494 100644 --- a/erpnext/crm/doctype/contract/test_contract.py +++ b/erpnext/crm/doctype/contract/test_contract.py @@ -1,7 +1,5 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2018, Frappe Technologies Pvt. Ltd. and Contributors # See license.txt -from __future__ import unicode_literals import unittest diff --git a/erpnext/crm/doctype/contract_fulfilment_checklist/contract_fulfilment_checklist.py b/erpnext/crm/doctype/contract_fulfilment_checklist/contract_fulfilment_checklist.py index ae56f93fc84..4e4e9986d6b 100644 --- a/erpnext/crm/doctype/contract_fulfilment_checklist/contract_fulfilment_checklist.py +++ b/erpnext/crm/doctype/contract_fulfilment_checklist/contract_fulfilment_checklist.py @@ -1,8 +1,6 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2018, Frappe Technologies Pvt. Ltd. and contributors # For license information, please see license.txt -from __future__ import unicode_literals from frappe.model.document import Document diff --git a/erpnext/crm/doctype/contract_fulfilment_checklist/test_contract_fulfilment_checklist.py b/erpnext/crm/doctype/contract_fulfilment_checklist/test_contract_fulfilment_checklist.py index 82e7ad35c9e..dfcbdfc9f96 100644 --- a/erpnext/crm/doctype/contract_fulfilment_checklist/test_contract_fulfilment_checklist.py +++ b/erpnext/crm/doctype/contract_fulfilment_checklist/test_contract_fulfilment_checklist.py @@ -1,7 +1,5 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2018, Frappe Technologies Pvt. Ltd. and Contributors # See license.txt -from __future__ import unicode_literals import unittest diff --git a/erpnext/crm/doctype/contract_template/contract_template.py b/erpnext/crm/doctype/contract_template/contract_template.py index fc1845c372d..7439e4c9171 100644 --- a/erpnext/crm/doctype/contract_template/contract_template.py +++ b/erpnext/crm/doctype/contract_template/contract_template.py @@ -1,15 +1,12 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2018, Frappe Technologies Pvt. Ltd. and contributors # For license information, please see license.txt -from __future__ import unicode_literals import json import frappe from frappe.model.document import Document from frappe.utils.jinja import validate_template -from six import string_types class ContractTemplate(Document): @@ -19,7 +16,7 @@ class ContractTemplate(Document): @frappe.whitelist() def get_contract_template(template_name, doc): - if isinstance(doc, string_types): + if isinstance(doc, str): doc = json.loads(doc) contract_template = frappe.get_doc("Contract Template", template_name) diff --git a/erpnext/crm/doctype/contract_template/test_contract_template.py b/erpnext/crm/doctype/contract_template/test_contract_template.py index 50655054c85..773d81e6584 100644 --- a/erpnext/crm/doctype/contract_template/test_contract_template.py +++ b/erpnext/crm/doctype/contract_template/test_contract_template.py @@ -1,7 +1,5 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2018, Frappe Technologies Pvt. Ltd. and Contributors # See license.txt -from __future__ import unicode_literals import unittest diff --git a/erpnext/crm/doctype/contract_template_fulfilment_terms/contract_template_fulfilment_terms.py b/erpnext/crm/doctype/contract_template_fulfilment_terms/contract_template_fulfilment_terms.py index 28f844d0970..18600d9918a 100644 --- a/erpnext/crm/doctype/contract_template_fulfilment_terms/contract_template_fulfilment_terms.py +++ b/erpnext/crm/doctype/contract_template_fulfilment_terms/contract_template_fulfilment_terms.py @@ -1,8 +1,6 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2018, Frappe Technologies Pvt. Ltd. and contributors # For license information, please see license.txt -from __future__ import unicode_literals from frappe.model.document import Document diff --git a/erpnext/crm/doctype/email_campaign/email_campaign.py b/erpnext/crm/doctype/email_campaign/email_campaign.py index 4b74f25ead7..d44443237e8 100644 --- a/erpnext/crm/doctype/email_campaign/email_campaign.py +++ b/erpnext/crm/doctype/email_campaign/email_campaign.py @@ -1,8 +1,6 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2019, Frappe Technologies Pvt. Ltd. and contributors # For license information, please see license.txt -from __future__ import unicode_literals import frappe from frappe import _ diff --git a/erpnext/crm/doctype/email_campaign/test_email_campaign.py b/erpnext/crm/doctype/email_campaign/test_email_campaign.py index f68b8c6d290..997d903c578 100644 --- a/erpnext/crm/doctype/email_campaign/test_email_campaign.py +++ b/erpnext/crm/doctype/email_campaign/test_email_campaign.py @@ -1,7 +1,5 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2019, Frappe Technologies Pvt. Ltd. and Contributors # See license.txt -from __future__ import unicode_literals # import frappe import unittest diff --git a/erpnext/crm/doctype/lead/lead.js b/erpnext/crm/doctype/lead/lead.js index 95cf03241bc..999599ce95b 100644 --- a/erpnext/crm/doctype/lead/lead.js +++ b/erpnext/crm/doctype/lead/lead.js @@ -51,7 +51,7 @@ erpnext.LeadController = class LeadController extends frappe.ui.form.Controller } } - add_lead_to_prospect (frm) { + add_lead_to_prospect () { frappe.prompt([ { fieldname: 'prospect', @@ -65,7 +65,7 @@ erpnext.LeadController = class LeadController extends frappe.ui.form.Controller frappe.call({ method: 'erpnext.crm.doctype.lead.lead.add_lead_to_prospect', args: { - 'lead': frm.doc.name, + 'lead': cur_frm.doc.name, 'prospect': data.prospect }, callback: function(r) { @@ -79,41 +79,41 @@ erpnext.LeadController = class LeadController extends frappe.ui.form.Controller }, __('Add Lead to Prospect'), __('Add')); } - make_customer (frm) { + make_customer () { frappe.model.open_mapped_doc({ method: "erpnext.crm.doctype.lead.lead.make_customer", - frm: frm + frm: cur_frm }) } - make_opportunity (frm) { + make_opportunity () { frappe.model.open_mapped_doc({ method: "erpnext.crm.doctype.lead.lead.make_opportunity", - frm: frm + frm: cur_frm }) } - make_quotation (frm) { + make_quotation () { frappe.model.open_mapped_doc({ method: "erpnext.crm.doctype.lead.lead.make_quotation", - frm: frm + frm: cur_frm }) } - make_prospect (frm) { + make_prospect () { frappe.model.with_doctype("Prospect", function() { let prospect = frappe.model.get_new_doc("Prospect"); - prospect.company_name = frm.doc.company_name; - prospect.no_of_employees = frm.doc.no_of_employees; - prospect.industry = frm.doc.industry; - prospect.market_segment = frm.doc.market_segment; - prospect.territory = frm.doc.territory; - prospect.fax = frm.doc.fax; - prospect.website = frm.doc.website; - prospect.prospect_owner = frm.doc.lead_owner; + prospect.company_name = cur_frm.doc.company_name; + prospect.no_of_employees = cur_frm.doc.no_of_employees; + prospect.industry = cur_frm.doc.industry; + prospect.market_segment = cur_frm.doc.market_segment; + prospect.territory = cur_frm.doc.territory; + prospect.fax = cur_frm.doc.fax; + prospect.website = cur_frm.doc.website; + prospect.prospect_owner = cur_frm.doc.lead_owner; let lead_prospect_row = frappe.model.add_child(prospect, 'prospect_lead'); - lead_prospect_row.lead = frm.doc.name; + lead_prospect_row.lead = cur_frm.doc.name; frappe.set_route("Form", "Prospect", prospect.name); }); diff --git a/erpnext/crm/doctype/lead/lead.py b/erpnext/crm/doctype/lead/lead.py index 5cf110ff27b..c590523a4f8 100644 --- a/erpnext/crm/doctype/lead/lead.py +++ b/erpnext/crm/doctype/lead/lead.py @@ -1,7 +1,6 @@ # Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors # License: GNU General Public License v3. See license.txt -from __future__ import unicode_literals import frappe from frappe import _ diff --git a/erpnext/crm/doctype/lead/lead_dashboard.py b/erpnext/crm/doctype/lead/lead_dashboard.py index 5edf2b62382..017390dc83e 100644 --- a/erpnext/crm/doctype/lead/lead_dashboard.py +++ b/erpnext/crm/doctype/lead/lead_dashboard.py @@ -1,6 +1,3 @@ -from __future__ import unicode_literals - - def get_data(): return { 'fieldname': 'lead', diff --git a/erpnext/crm/doctype/lead/test_lead.py b/erpnext/crm/doctype/lead/test_lead.py index 833c43e0596..56bfc8f1457 100644 --- a/erpnext/crm/doctype/lead/test_lead.py +++ b/erpnext/crm/doctype/lead/test_lead.py @@ -1,7 +1,6 @@ # Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors # License: GNU General Public License v3. See license.txt -from __future__ import unicode_literals import unittest diff --git a/erpnext/crm/doctype/lead_source/lead_source.py b/erpnext/crm/doctype/lead_source/lead_source.py index 8de1c4301b1..d9e00286513 100644 --- a/erpnext/crm/doctype/lead_source/lead_source.py +++ b/erpnext/crm/doctype/lead_source/lead_source.py @@ -1,8 +1,6 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2021, Frappe Technologies Pvt. Ltd. and contributors # For license information, please see license.txt -from __future__ import unicode_literals # import frappe from frappe.model.document import Document diff --git a/erpnext/crm/doctype/lead_source/test_lead_source.py b/erpnext/crm/doctype/lead_source/test_lead_source.py index ecf61171e99..1363d1f4649 100644 --- a/erpnext/crm/doctype/lead_source/test_lead_source.py +++ b/erpnext/crm/doctype/lead_source/test_lead_source.py @@ -1,7 +1,5 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2021, Frappe Technologies Pvt. Ltd. and Contributors # See license.txt -from __future__ import unicode_literals # import frappe import unittest diff --git a/erpnext/crm/doctype/linkedin_settings/linkedin_settings.py b/erpnext/crm/doctype/linkedin_settings/linkedin_settings.py index 03c9d9c762c..8fd4978715f 100644 --- a/erpnext/crm/doctype/linkedin_settings/linkedin_settings.py +++ b/erpnext/crm/doctype/linkedin_settings/linkedin_settings.py @@ -1,8 +1,6 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2020, Frappe Technologies Pvt. Ltd. and contributors # For license information, please see license.txt -from __future__ import unicode_literals import frappe import requests diff --git a/erpnext/crm/doctype/linkedin_settings/test_linkedin_settings.py b/erpnext/crm/doctype/linkedin_settings/test_linkedin_settings.py index 1d86f0c66fe..09732e405ee 100644 --- a/erpnext/crm/doctype/linkedin_settings/test_linkedin_settings.py +++ b/erpnext/crm/doctype/linkedin_settings/test_linkedin_settings.py @@ -1,7 +1,5 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2020, Frappe Technologies Pvt. Ltd. and Contributors # See license.txt -from __future__ import unicode_literals # import frappe import unittest diff --git a/erpnext/crm/doctype/lost_reason_detail/lost_reason_detail.py b/erpnext/crm/doctype/lost_reason_detail/lost_reason_detail.py index 88abd423cfa..51e4d5c506c 100644 --- a/erpnext/crm/doctype/lost_reason_detail/lost_reason_detail.py +++ b/erpnext/crm/doctype/lost_reason_detail/lost_reason_detail.py @@ -1,8 +1,6 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2018, Frappe Technologies Pvt. Ltd. and contributors # For license information, please see license.txt -from __future__ import unicode_literals from frappe.model.document import Document diff --git a/erpnext/crm/doctype/market_segment/market_segment.py b/erpnext/crm/doctype/market_segment/market_segment.py index 92adf56876c..766be857040 100644 --- a/erpnext/crm/doctype/market_segment/market_segment.py +++ b/erpnext/crm/doctype/market_segment/market_segment.py @@ -1,8 +1,6 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2018, Frappe Technologies Pvt. Ltd. and contributors # For license information, please see license.txt -from __future__ import unicode_literals from frappe.model.document import Document diff --git a/erpnext/crm/doctype/market_segment/test_market_segment.py b/erpnext/crm/doctype/market_segment/test_market_segment.py index b95cc4cde0d..20b73b15311 100644 --- a/erpnext/crm/doctype/market_segment/test_market_segment.py +++ b/erpnext/crm/doctype/market_segment/test_market_segment.py @@ -1,7 +1,5 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2018, Frappe Technologies Pvt. Ltd. and Contributors # See license.txt -from __future__ import unicode_literals import unittest diff --git a/erpnext/crm/doctype/opportunity/opportunity.js b/erpnext/crm/doctype/opportunity/opportunity.js index 3866fc263e6..f8376e6ca94 100644 --- a/erpnext/crm/doctype/opportunity/opportunity.js +++ b/erpnext/crm/doctype/opportunity/opportunity.js @@ -132,10 +132,43 @@ frappe.ui.form.on("Opportunity", { } }, + currency: function(frm) { + let company_currency = erpnext.get_currency(frm.doc.company); + if (company_currency != frm.doc.company) { + frappe.call({ + method: "erpnext.setup.utils.get_exchange_rate", + args: { + from_currency: frm.doc.currency, + to_currency: company_currency + }, + callback: function(r) { + if (r.message) { + frm.set_value('conversion_rate', flt(r.message)); + frm.set_df_property('conversion_rate', 'description', '1 ' + frm.doc.currency + + ' = [?] ' + company_currency); + } + } + }); + } else { + frm.set_value('conversion_rate', 1.0); + frm.set_df_property('conversion_rate', 'hidden', 1); + frm.set_df_property('conversion_rate', 'description', ''); + } + + frm.trigger('opportunity_amount'); + frm.trigger('set_dynamic_field_label'); + }, + + opportunity_amount: function(frm) { + frm.set_value('base_opportunity_amount', flt(frm.doc.opportunity_amount) * flt(frm.doc.conversion_rate)); + }, + set_dynamic_field_label: function(frm){ if (frm.doc.opportunity_from) { frm.set_df_property("party_name", "label", frm.doc.opportunity_from); } + frm.trigger('change_grid_labels'); + frm.trigger('change_form_labels'); }, make_supplier_quotation: function(frm) { @@ -152,6 +185,62 @@ frappe.ui.form.on("Opportunity", { }) }, + change_form_labels: function(frm) { + let company_currency = erpnext.get_currency(frm.doc.company); + frm.set_currency_labels(["base_opportunity_amount", "base_total", "base_grand_total"], company_currency); + frm.set_currency_labels(["opportunity_amount", "total", "grand_total"], frm.doc.currency); + + // toggle fields + frm.toggle_display(["conversion_rate", "base_opportunity_amount", "base_total", "base_grand_total"], + frm.doc.currency != company_currency); + }, + + change_grid_labels: function(frm) { + let company_currency = erpnext.get_currency(frm.doc.company); + frm.set_currency_labels(["base_rate", "base_amount"], company_currency, "items"); + frm.set_currency_labels(["rate", "amount"], frm.doc.currency, "items"); + + let item_grid = frm.fields_dict.items.grid; + $.each(["base_rate", "base_amount"], function(i, fname) { + if(frappe.meta.get_docfield(item_grid.doctype, fname)) + item_grid.set_column_disp(fname, frm.doc.currency != company_currency); + }); + frm.refresh_fields(); + }, + + calculate_total: function(frm) { + let total = 0, base_total = 0, grand_total = 0, base_grand_total = 0; + frm.doc.items.forEach(item => { + total += item.amount; + base_total += item.base_amount; + }) + + base_grand_total = base_total + frm.doc.base_opportunity_amount; + grand_total = total + frm.doc.opportunity_amount; + + frm.set_value({ + 'total': flt(total), + 'base_total': flt(base_total), + 'grand_total': flt(grand_total), + 'base_grand_total': flt(base_grand_total) + }); + } + +}); +frappe.ui.form.on("Opportunity Item", { + calculate: function(frm, cdt, cdn) { + let row = frappe.get_doc(cdt, cdn); + frappe.model.set_value(cdt, cdn, "amount", flt(row.qty) * flt(row.rate)); + frappe.model.set_value(cdt, cdn, "base_rate", flt(frm.doc.conversion_rate) * flt(row.rate)); + frappe.model.set_value(cdt, cdn, "base_amount", flt(frm.doc.conversion_rate) * flt(row.amount)); + frm.trigger("calculate_total"); + }, + qty: function(frm, cdt, cdn) { + frm.trigger("calculate", cdt, cdn); + }, + rate: function(frm, cdt, cdn) { + frm.trigger("calculate", cdt, cdn); + } }) // TODO commonify this code @@ -169,6 +258,7 @@ erpnext.crm.Opportunity = class Opportunity extends frappe.ui.form.Controller { } this.setup_queries(); + this.frm.trigger('currency'); } setup_queries() { diff --git a/erpnext/crm/doctype/opportunity/opportunity.json b/erpnext/crm/doctype/opportunity/opportunity.json index 12a564a9cb3..feb6044d64c 100644 --- a/erpnext/crm/doctype/opportunity/opportunity.json +++ b/erpnext/crm/doctype/opportunity/opportunity.json @@ -23,7 +23,6 @@ "status", "converted_by", "sales_stage", - "order_lost_reason", "first_response_time", "expected_closing", "next_contact", @@ -33,12 +32,20 @@ "to_discuss", "section_break_14", "currency", - "opportunity_amount", + "conversion_rate", + "base_opportunity_amount", "with_items", "column_break_17", "probability", + "opportunity_amount", "items_section", "items", + "section_break_32", + "base_total", + "base_grand_total", + "column_break_33", + "total", + "grand_total", "contact_info", "customer_address", "address_display", @@ -56,7 +63,11 @@ "transaction_date", "language", "amended_from", - "lost_reasons" + "lost_detail_section", + "lost_reasons", + "order_lost_reason", + "column_break_56", + "competitors" ], "fields": [ { @@ -146,10 +157,9 @@ "reqd": 1 }, { - "depends_on": "eval:doc.status===\"Lost\"", "fieldname": "order_lost_reason", "fieldtype": "Small Text", - "label": "Lost Reason", + "label": "Detailed Reason", "no_copy": 1, "read_only": 1 }, @@ -401,6 +411,7 @@ "width": "150px" }, { + "depends_on": "eval:doc.status===\"Lost\"", "fieldname": "lost_reasons", "fieldtype": "Table MultiSelect", "label": "Lost Reasons", @@ -425,15 +436,86 @@ "fieldtype": "Link", "label": "Print Language", "options": "Language" + }, + { + "fieldname": "base_opportunity_amount", + "fieldtype": "Currency", + "label": "Opportunity Amount (Company Currency)", + "options": "Company:company:default_currency", + "print_hide": 1, + "read_only": 1 + }, + { + "depends_on": "with_items", + "fieldname": "section_break_32", + "fieldtype": "Section Break", + "hide_border": 1 + }, + { + "fieldname": "base_total", + "fieldtype": "Currency", + "label": "Total (Company Currency)", + "options": "Company:company:default_currency", + "print_hide": 1, + "read_only": 1 + }, + { + "fieldname": "total", + "fieldtype": "Currency", + "label": "Total", + "options": "currency", + "read_only": 1 + }, + { + "fieldname": "conversion_rate", + "fieldtype": "Float", + "label": "Exchange Rate" + }, + { + "fieldname": "column_break_33", + "fieldtype": "Column Break" + }, + { + "fieldname": "base_grand_total", + "fieldtype": "Currency", + "label": "Grand Total (Company Currency)", + "options": "Company:company:default_currency", + "print_hide": 1, + "read_only": 1 + }, + { + "fieldname": "grand_total", + "fieldtype": "Currency", + "label": "Grand Total", + "options": "currency", + "read_only": 1 + }, + { + "fieldname": "lost_detail_section", + "fieldtype": "Section Break", + "label": "Lost Reasons" + }, + { + "fieldname": "column_break_56", + "fieldtype": "Column Break" + }, + { + "fieldname": "competitors", + "fieldtype": "Table MultiSelect", + "label": "Competitors", + "options": "Competitor Detail", + "read_only": 1 } ], "icon": "fa fa-info-sign", "idx": 195, "links": [], - "modified": "2021-08-25 10:28:24.923543", + "migration_hash": "d87c646ea2579b6900197fd41e6c5c5a", + "modified": "2021-10-21 11:04:30.151379", "modified_by": "Administrator", "module": "CRM", "name": "Opportunity", + "naming_rule": "By \"Naming Series\" field", "owner": "Administrator", "permissions": [ { diff --git a/erpnext/crm/doctype/opportunity/opportunity.py b/erpnext/crm/doctype/opportunity/opportunity.py index 0b3f50897ab..0bef80a749d 100644 --- a/erpnext/crm/doctype/opportunity/opportunity.py +++ b/erpnext/crm/doctype/opportunity/opportunity.py @@ -1,7 +1,6 @@ # Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors # License: GNU General Public License v3. See license.txt -from __future__ import unicode_literals import json @@ -9,9 +8,8 @@ import frappe from frappe import _ from frappe.email.inbox import link_communication_to_document from frappe.model.mapper import get_mapped_doc -from frappe.utils import cint, cstr, get_fullname +from frappe.utils import cint, cstr, flt, get_fullname -from erpnext.accounts.party import get_party_account_currency from erpnext.setup.utils import get_exchange_rate from erpnext.utilities.transaction_base import TransactionBase @@ -34,6 +32,7 @@ class Opportunity(TransactionBase): self.validate_item_details() self.validate_uom_is_integer("uom", "qty") self.validate_cust_name() + self.map_fields() if not self.title: self.title = self.customer_name @@ -41,6 +40,32 @@ class Opportunity(TransactionBase): if not self.with_items: self.items = [] + else: + self.calculate_totals() + + def map_fields(self): + for field in self.meta.fields: + if not self.get(field.fieldname): + try: + value = frappe.db.get_value(self.opportunity_from, self.party_name, field.fieldname) + frappe.db.set(self, field.fieldname, value) + except Exception: + continue + + def calculate_totals(self): + total = base_total = 0 + for item in self.get('items'): + item.amount = flt(item.rate) * flt(item.qty) + item.base_rate = flt(self.conversion_rate * item.rate) + item.base_amount = flt(self.conversion_rate * item.amount) + total += item.amount + base_total += item.base_amount + + self.total = flt(total) + self.base_total = flt(base_total) + self.grand_total = flt(self.total) + flt(self.opportunity_amount) + self.base_grand_total = flt(self.base_total) + flt(self.base_opportunity_amount) + def make_new_lead_if_required(self): """Set lead against new opportunity""" if (not self.get("party_name")) and self.contact_email: @@ -91,16 +116,20 @@ class Opportunity(TransactionBase): self.party_name = lead_name @frappe.whitelist() - def declare_enquiry_lost(self, lost_reasons_list, detailed_reason=None): + def declare_enquiry_lost(self, lost_reasons_list, competitors, detailed_reason=None): if not self.has_active_quotation(): - frappe.db.set(self, 'status', 'Lost') + self.status = 'Lost' + self.lost_reasons = self.competitors = [] if detailed_reason: - frappe.db.set(self, 'order_lost_reason', detailed_reason) + self.order_lost_reason = detailed_reason for reason in lost_reasons_list: self.append('lost_reasons', reason) + for competitor in competitors: + self.append('competitors', competitor) + self.save() else: @@ -224,13 +253,6 @@ def make_quotation(source_name, target_doc=None): company_currency = frappe.get_cached_value('Company', quotation.company, "default_currency") - if quotation.quotation_to == 'Customer' and quotation.party_name: - party_account_currency = get_party_account_currency("Customer", quotation.party_name, quotation.company) - else: - party_account_currency = company_currency - - quotation.currency = party_account_currency or company_currency - if company_currency == quotation.currency: exchange_rate = 1 else: @@ -254,7 +276,7 @@ def make_quotation(source_name, target_doc=None): "doctype": "Quotation", "field_map": { "opportunity_from": "quotation_to", - "name": "enq_no", + "name": "enq_no" } }, "Opportunity Item": { @@ -295,6 +317,8 @@ def make_request_for_quotation(source_name, target_doc=None): @frappe.whitelist() def make_customer(source_name, target_doc=None): def set_missing_values(source, target): + target.opportunity_name = source.name + if source.opportunity_from == "Lead": target.lead_name = source.party_name diff --git a/erpnext/crm/doctype/opportunity/opportunity_dashboard.py b/erpnext/crm/doctype/opportunity/opportunity_dashboard.py index 693a86cfcdf..708fb12f1a3 100644 --- a/erpnext/crm/doctype/opportunity/opportunity_dashboard.py +++ b/erpnext/crm/doctype/opportunity/opportunity_dashboard.py @@ -1,6 +1,3 @@ -from __future__ import unicode_literals - - def get_data(): return { 'fieldname': 'opportunity', diff --git a/erpnext/crm/doctype/opportunity/test_opportunity.py b/erpnext/crm/doctype/opportunity/test_opportunity.py index 347bf6366d2..6e6fed58cbe 100644 --- a/erpnext/crm/doctype/opportunity/test_opportunity.py +++ b/erpnext/crm/doctype/opportunity/test_opportunity.py @@ -1,6 +1,5 @@ # Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors and Contributors # See license.txt -from __future__ import unicode_literals import unittest @@ -63,6 +62,10 @@ class TestOpportunity(unittest.TestCase): self.assertEqual(opp_doc.opportunity_from, "Customer") self.assertEqual(opp_doc.party_name, customer.name) + def test_opportunity_item(self): + opportunity_doc = make_opportunity(with_items=1, rate=1100, qty=2) + self.assertEqual(opportunity_doc.total, 2200) + def make_opportunity(**args): args = frappe._dict(args) @@ -71,6 +74,7 @@ def make_opportunity(**args): "company": args.company or "_Test Company", "opportunity_from": args.opportunity_from or "Customer", "opportunity_type": "Sales", + "conversion_rate": 1.0, "with_items": args.with_items or 0, "transaction_date": today() }) @@ -85,6 +89,7 @@ def make_opportunity(**args): opp_doc.append('items', { "item_code": args.item_code or "_Test Item", "qty": args.qty or 1, + "rate": args.rate or 1000, "uom": "_Test UOM" }) diff --git a/erpnext/crm/doctype/opportunity_item/opportunity_item.json b/erpnext/crm/doctype/opportunity_item/opportunity_item.json index 65e8433583b..1b4973c1b2b 100644 --- a/erpnext/crm/doctype/opportunity_item/opportunity_item.json +++ b/erpnext/crm/doctype/opportunity_item/opportunity_item.json @@ -1,469 +1,177 @@ { - "allow_copy": 0, - "allow_events_in_timeline": 0, - "allow_guest_to_view": 0, - "allow_import": 0, - "allow_rename": 0, - "beta": 0, - "creation": "2013-02-22 01:27:51", - "custom": 0, - "docstatus": 0, - "doctype": "DocType", - "editable_grid": 1, - "engine": "InnoDB", + "actions": [], + "creation": "2013-02-22 01:27:51", + "doctype": "DocType", + "editable_grid": 1, + "engine": "InnoDB", + "field_order": [ + "item_code", + "item_name", + "col_break1", + "uom", + "qty", + "section_break_6", + "brand", + "item_group", + "description", + "column_break_8", + "image", + "image_view", + "quantity_and_rate_section", + "base_rate", + "base_amount", + "column_break_16", + "rate", + "amount" + ], "fields": [ { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "item_code", - "fieldtype": "Link", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 1, - "in_standard_filter": 0, - "label": "Item Code", - "length": 0, - "no_copy": 0, - "oldfieldname": "item_code", - "oldfieldtype": "Link", - "options": "Item", - "permlevel": 0, - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 - }, + "fieldname": "item_code", + "fieldtype": "Link", + "in_list_view": 1, + "label": "Item Code", + "oldfieldname": "item_code", + "oldfieldtype": "Link", + "options": "Item" + }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "col_break1", - "fieldtype": "Column Break", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "length": 0, - "no_copy": 0, - "permlevel": 0, - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 - }, + "fieldname": "col_break1", + "fieldtype": "Column Break" + }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "qty", - "fieldtype": "Float", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 1, - "in_standard_filter": 0, - "label": "Qty", - "length": 0, - "no_copy": 0, - "oldfieldname": "qty", - "oldfieldtype": "Currency", - "permlevel": 0, - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 - }, + "default": "1", + "fieldname": "qty", + "fieldtype": "Float", + "in_list_view": 1, + "label": "Qty", + "oldfieldname": "qty", + "oldfieldtype": "Currency" + }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "description": "", - "fieldname": "item_group", - "fieldtype": "Link", - "hidden": 1, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "label": "Item Group", - "length": 0, - "no_copy": 0, - "oldfieldname": "item_group", - "oldfieldtype": "Link", - "options": "Item Group", - "permlevel": 0, - "print_hide": 1, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 - }, + "fieldname": "item_group", + "fieldtype": "Link", + "hidden": 1, + "label": "Item Group", + "oldfieldname": "item_group", + "oldfieldtype": "Link", + "options": "Item Group", + "print_hide": 1 + }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "brand", - "fieldtype": "Link", - "hidden": 1, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "label": "Brand", - "length": 0, - "no_copy": 0, - "oldfieldname": "brand", - "oldfieldtype": "Link", - "options": "Brand", - "permlevel": 0, - "print_hide": 1, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 - }, + "fieldname": "brand", + "fieldtype": "Link", + "hidden": 1, + "label": "Brand", + "oldfieldname": "brand", + "oldfieldtype": "Link", + "options": "Brand", + "print_hide": 1 + }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "section_break_6", - "fieldtype": "Section Break", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "length": 0, - "no_copy": 0, - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 - }, + "collapsible": 1, + "fieldname": "section_break_6", + "fieldtype": "Section Break", + "label": "Description" + }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "uom", - "fieldtype": "Link", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "label": "UOM", - "length": 0, - "no_copy": 0, - "oldfieldname": "uom", - "oldfieldtype": "Link", - "options": "UOM", - "permlevel": 0, - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 - }, + "fieldname": "uom", + "fieldtype": "Link", + "label": "UOM", + "oldfieldname": "uom", + "oldfieldtype": "Link", + "options": "UOM" + }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "item_name", - "fieldtype": "Data", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 1, - "in_list_view": 1, - "in_standard_filter": 0, - "label": "Item Name", - "length": 0, - "no_copy": 0, - "oldfieldname": "item_name", - "oldfieldtype": "Data", - "permlevel": 0, - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 - }, + "fieldname": "item_name", + "fieldtype": "Data", + "in_global_search": 1, + "label": "Item Name", + "oldfieldname": "item_name", + "oldfieldtype": "Data" + }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "description", - "fieldtype": "Text Editor", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "label": "Description", - "length": 0, - "no_copy": 0, - "oldfieldname": "description", - "oldfieldtype": "Text", - "permlevel": 0, - "print_hide": 0, - "print_hide_if_no_value": 0, - "print_width": "300px", - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0, + "fieldname": "description", + "fieldtype": "Text Editor", + "label": "Description", + "oldfieldname": "description", + "oldfieldtype": "Text", + "print_width": "300px", "width": "300px" - }, + }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "column_break_8", - "fieldtype": "Column Break", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "length": 0, - "no_copy": 0, - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 - }, + "fieldname": "column_break_8", + "fieldtype": "Column Break" + }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "image", - "fieldtype": "Attach", - "hidden": 1, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "label": "Image", - "length": 0, - "no_copy": 0, - "options": "", - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 - }, + "fieldname": "image", + "fieldtype": "Attach", + "hidden": 1, + "label": "Image" + }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "image_view", - "fieldtype": "Image", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "label": "Image View", - "length": 0, - "no_copy": 0, - "options": "image", - "permlevel": 0, - "precision": "", - "print_hide": 1, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 - }, + "fieldname": "image_view", + "fieldtype": "Image", + "label": "Image View", + "options": "image", + "print_hide": 1 + }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "basic_rate", - "fieldtype": "Currency", - "hidden": 1, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "label": "Basic Rate", - "length": 0, - "no_copy": 0, - "oldfieldname": "basic_rate", - "oldfieldtype": "Currency", - "options": "Company:company:default_currency", - "permlevel": 0, - "print_hide": 1, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 + "fieldname": "rate", + "fieldtype": "Currency", + "in_list_view": 1, + "label": "Rate", + "options": "currency", + "reqd": 1 + }, + { + "fieldname": "quantity_and_rate_section", + "fieldtype": "Section Break", + "label": "Quantity and Rate" + }, + { + "fieldname": "base_amount", + "fieldtype": "Currency", + "label": "Amount (Company Currency)", + "options": "Company:company:default_currency", + "print_hide": 1, + "read_only": 1, + "reqd": 1 + }, + { + "fieldname": "column_break_16", + "fieldtype": "Column Break" + }, + { + "fieldname": "amount", + "fieldtype": "Currency", + "in_list_view": 1, + "label": "Amount", + "options": "currency", + "read_only": 1, + "reqd": 1 + }, + { + "fieldname": "base_rate", + "fieldtype": "Currency", + "label": "Rate (Company Currency)", + "oldfieldname": "basic_rate", + "oldfieldtype": "Currency", + "options": "Company:company:default_currency", + "print_hide": 1, + "read_only": 1, + "reqd": 1 } - ], - "has_web_view": 0, - "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": "2018-12-28 15:43:09.382012", - "modified_by": "Administrator", - "module": "CRM", - "name": "Opportunity Item", - "owner": "Administrator", - "permissions": [], - "quick_entry": 0, - "read_only": 0, - "read_only_onload": 0, - "show_name_in_global_search": 0, - "track_changes": 1, - "track_seen": 0, - "track_views": 0 + ], + "idx": 1, + "istable": 1, + "links": [], + "modified": "2021-07-30 16:39:09.775720", + "modified_by": "Administrator", + "module": "CRM", + "name": "Opportunity Item", + "owner": "Administrator", + "permissions": [], + "sort_field": "modified", + "sort_order": "DESC", + "track_changes": 1 } \ No newline at end of file diff --git a/erpnext/crm/doctype/opportunity_item/opportunity_item.py b/erpnext/crm/doctype/opportunity_item/opportunity_item.py index 225cfe9d324..4d285870ce5 100644 --- a/erpnext/crm/doctype/opportunity_item/opportunity_item.py +++ b/erpnext/crm/doctype/opportunity_item/opportunity_item.py @@ -1,8 +1,6 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors and contributors # For license information, please see license.txt -from __future__ import unicode_literals from frappe.model.document import Document diff --git a/erpnext/crm/doctype/opportunity_lost_reason/opportunity_lost_reason.py b/erpnext/crm/doctype/opportunity_lost_reason/opportunity_lost_reason.py index b25f02afffd..84a9a52b5b8 100644 --- a/erpnext/crm/doctype/opportunity_lost_reason/opportunity_lost_reason.py +++ b/erpnext/crm/doctype/opportunity_lost_reason/opportunity_lost_reason.py @@ -1,8 +1,6 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2018, Frappe Technologies Pvt. Ltd. and contributors # For license information, please see license.txt -from __future__ import unicode_literals from frappe.model.document import Document diff --git a/erpnext/crm/doctype/opportunity_lost_reason_detail/opportunity_lost_reason_detail.py b/erpnext/crm/doctype/opportunity_lost_reason_detail/opportunity_lost_reason_detail.py index 4bb5c54b1d9..d5721850d0c 100644 --- a/erpnext/crm/doctype/opportunity_lost_reason_detail/opportunity_lost_reason_detail.py +++ b/erpnext/crm/doctype/opportunity_lost_reason_detail/opportunity_lost_reason_detail.py @@ -1,8 +1,6 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2020, Frappe Technologies Pvt. Ltd. and contributors # For license information, please see license.txt -from __future__ import unicode_literals # import frappe from frappe.model.document import Document diff --git a/erpnext/crm/doctype/opportunity_type/opportunity_type.py b/erpnext/crm/doctype/opportunity_type/opportunity_type.py index 5b64e980965..1bb31ec859a 100644 --- a/erpnext/crm/doctype/opportunity_type/opportunity_type.py +++ b/erpnext/crm/doctype/opportunity_type/opportunity_type.py @@ -1,8 +1,6 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2017, Frappe Technologies Pvt. Ltd. and contributors # For license information, please see license.txt -from __future__ import unicode_literals from frappe.model.document import Document diff --git a/erpnext/crm/doctype/opportunity_type/test_opportunity_type.py b/erpnext/crm/doctype/opportunity_type/test_opportunity_type.py index f86a70e8cfa..ae0d7827cc7 100644 --- a/erpnext/crm/doctype/opportunity_type/test_opportunity_type.py +++ b/erpnext/crm/doctype/opportunity_type/test_opportunity_type.py @@ -1,7 +1,5 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2017, Frappe Technologies Pvt. Ltd. and Contributors # See license.txt -from __future__ import unicode_literals import unittest diff --git a/erpnext/crm/doctype/prospect/prospect.json b/erpnext/crm/doctype/prospect/prospect.json index 3d6fba5123a..c9554ba31af 100644 --- a/erpnext/crm/doctype/prospect/prospect.json +++ b/erpnext/crm/doctype/prospect/prospect.json @@ -20,6 +20,7 @@ "website", "column_break_13", "prospect_owner", + "company", "leads_section", "prospect_lead", "address_and_contact_section", @@ -153,14 +154,22 @@ "fieldname": "address_and_contact_section", "fieldtype": "Section Break", "label": "Address and Contact" + }, + { + "fieldname": "company", + "fieldtype": "Link", + "label": "Company", + "options": "Company", + "reqd": 1 } ], "index_web_pages_for_search": 1, "links": [], - "modified": "2021-08-27 16:24:42.961967", + "modified": "2021-11-01 13:10:36.759249", "modified_by": "Administrator", "module": "CRM", "name": "Prospect", + "naming_rule": "By fieldname", "owner": "Administrator", "permissions": [ { diff --git a/erpnext/crm/doctype/sales_stage/sales_stage.py b/erpnext/crm/doctype/sales_stage/sales_stage.py index e9e176f0871..d2099edd052 100644 --- a/erpnext/crm/doctype/sales_stage/sales_stage.py +++ b/erpnext/crm/doctype/sales_stage/sales_stage.py @@ -1,8 +1,6 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2018, Frappe Technologies Pvt. Ltd. and contributors # For license information, please see license.txt -from __future__ import unicode_literals from frappe.model.document import Document diff --git a/erpnext/crm/doctype/sales_stage/test_sales_stage.py b/erpnext/crm/doctype/sales_stage/test_sales_stage.py index 83d1f269fd7..d088f968f52 100644 --- a/erpnext/crm/doctype/sales_stage/test_sales_stage.py +++ b/erpnext/crm/doctype/sales_stage/test_sales_stage.py @@ -1,7 +1,5 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2018, Frappe Technologies Pvt. Ltd. and Contributors # See license.txt -from __future__ import unicode_literals import unittest diff --git a/erpnext/crm/doctype/social_media_post/social_media_post.py b/erpnext/crm/doctype/social_media_post/social_media_post.py index 14d4521e1e6..3f63c1dfaaa 100644 --- a/erpnext/crm/doctype/social_media_post/social_media_post.py +++ b/erpnext/crm/doctype/social_media_post/social_media_post.py @@ -1,8 +1,6 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2020, Frappe Technologies Pvt. Ltd. and contributors # For license information, please see license.txt -from __future__ import unicode_literals import datetime diff --git a/erpnext/crm/doctype/social_media_post/test_social_media_post.py b/erpnext/crm/doctype/social_media_post/test_social_media_post.py index c2d041898aa..75744767dca 100644 --- a/erpnext/crm/doctype/social_media_post/test_social_media_post.py +++ b/erpnext/crm/doctype/social_media_post/test_social_media_post.py @@ -1,7 +1,5 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2020, Frappe Technologies Pvt. Ltd. and Contributors # See license.txt -from __future__ import unicode_literals # import frappe import unittest diff --git a/erpnext/crm/doctype/twitter_settings/test_twitter_settings.py b/erpnext/crm/doctype/twitter_settings/test_twitter_settings.py index ff3163c559b..9dbce8f8aba 100644 --- a/erpnext/crm/doctype/twitter_settings/test_twitter_settings.py +++ b/erpnext/crm/doctype/twitter_settings/test_twitter_settings.py @@ -1,7 +1,5 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2020, Frappe Technologies Pvt. Ltd. and Contributors # See license.txt -from __future__ import unicode_literals # import frappe import unittest diff --git a/erpnext/crm/doctype/twitter_settings/twitter_settings.py b/erpnext/crm/doctype/twitter_settings/twitter_settings.py index 0205cca2b92..be7d9145c53 100644 --- a/erpnext/crm/doctype/twitter_settings/twitter_settings.py +++ b/erpnext/crm/doctype/twitter_settings/twitter_settings.py @@ -1,8 +1,6 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2020, Frappe Technologies Pvt. Ltd. and contributors # For license information, please see license.txt -from __future__ import unicode_literals import json diff --git a/erpnext/crm/doctype/utils.py b/erpnext/crm/doctype/utils.py index 0da0e0e71af..9b56170da31 100644 --- a/erpnext/crm/doctype/utils.py +++ b/erpnext/crm/doctype/utils.py @@ -1,4 +1,3 @@ - import frappe diff --git a/erpnext/crm/report/campaign_efficiency/campaign_efficiency.py b/erpnext/crm/report/campaign_efficiency/campaign_efficiency.py index 87f516b8c72..6f3e311f392 100644 --- a/erpnext/crm/report/campaign_efficiency/campaign_efficiency.py +++ b/erpnext/crm/report/campaign_efficiency/campaign_efficiency.py @@ -1,7 +1,6 @@ # Copyright (c) 2013, Frappe Technologies Pvt. Ltd. and contributors # For license information, please see license.txt -from __future__ import unicode_literals import frappe from frappe import _ diff --git a/erpnext/crm/report/first_response_time_for_opportunity/first_response_time_for_opportunity.py b/erpnext/crm/report/first_response_time_for_opportunity/first_response_time_for_opportunity.py index df57893ef49..ed6cefb2a32 100644 --- a/erpnext/crm/report/first_response_time_for_opportunity/first_response_time_for_opportunity.py +++ b/erpnext/crm/report/first_response_time_for_opportunity/first_response_time_for_opportunity.py @@ -1,7 +1,6 @@ # Copyright (c) 2013, Frappe Technologies Pvt. Ltd. and contributors # For license information, please see license.txt -from __future__ import unicode_literals import frappe diff --git a/erpnext/crm/report/lead_conversion_time/lead_conversion_time.py b/erpnext/crm/report/lead_conversion_time/lead_conversion_time.py index 71efdb96e75..1f43fa0c476 100644 --- a/erpnext/crm/report/lead_conversion_time/lead_conversion_time.py +++ b/erpnext/crm/report/lead_conversion_time/lead_conversion_time.py @@ -1,7 +1,6 @@ # Copyright (c) 2018, Frappe Technologies Pvt. Ltd. and contributors # For license information, please see license.txt -from __future__ import unicode_literals import frappe from frappe import _, msgprint diff --git a/erpnext/crm/report/lead_details/lead_details.py b/erpnext/crm/report/lead_details/lead_details.py index 11e82764278..09eba7c38a6 100644 --- a/erpnext/crm/report/lead_details/lead_details.py +++ b/erpnext/crm/report/lead_details/lead_details.py @@ -1,7 +1,6 @@ # Copyright (c) 2020, Frappe Technologies Pvt. Ltd. and contributors # For license information, please see license.txt -from __future__ import unicode_literals import frappe from frappe import _ diff --git a/erpnext/crm/report/lead_owner_efficiency/lead_owner_efficiency.py b/erpnext/crm/report/lead_owner_efficiency/lead_owner_efficiency.py index 5406eba6d8e..29322119ee4 100644 --- a/erpnext/crm/report/lead_owner_efficiency/lead_owner_efficiency.py +++ b/erpnext/crm/report/lead_owner_efficiency/lead_owner_efficiency.py @@ -1,7 +1,6 @@ # Copyright (c) 2013, Frappe Technologies Pvt. Ltd. and contributors # For license information, please see license.txt -from __future__ import unicode_literals from frappe import _ diff --git a/erpnext/crm/report/lost_opportunity/lost_opportunity.py b/erpnext/crm/report/lost_opportunity/lost_opportunity.py index b308ceb272d..60d4be85648 100644 --- a/erpnext/crm/report/lost_opportunity/lost_opportunity.py +++ b/erpnext/crm/report/lost_opportunity/lost_opportunity.py @@ -1,7 +1,6 @@ # Copyright (c) 2020, Frappe Technologies Pvt. Ltd. and contributors # For license information, please see license.txt -from __future__ import unicode_literals import frappe from frappe import _ diff --git a/erpnext/healthcare/doctype/body_part/__init__.py b/erpnext/crm/report/opportunity_summary_by_sales_stage/__init__.py similarity index 100% rename from erpnext/healthcare/doctype/body_part/__init__.py rename to erpnext/crm/report/opportunity_summary_by_sales_stage/__init__.py diff --git a/erpnext/crm/report/opportunity_summary_by_sales_stage/opportunity_summary_by_sales_stage.js b/erpnext/crm/report/opportunity_summary_by_sales_stage/opportunity_summary_by_sales_stage.js new file mode 100644 index 00000000000..116db2f5a27 --- /dev/null +++ b/erpnext/crm/report/opportunity_summary_by_sales_stage/opportunity_summary_by_sales_stage.js @@ -0,0 +1,65 @@ +// Copyright (c) 2016, Frappe Technologies Pvt. Ltd. and contributors +// For license information, please see license.txt +/* eslint-disable */ + +frappe.query_reports["Opportunity Summary by Sales Stage"] = { + "filters": [ + { + fieldname: "based_on", + label: __("Based On"), + fieldtype: "Select", + options: "Opportunity Owner\nSource\nOpportunity Type", + default: "Opportunity Owner" + }, + { + fieldname: "data_based_on", + label: __("Data Based On"), + fieldtype: "Select", + options: "Number\nAmount", + default: "Number" + }, + { + fieldname: "from_date", + label: __("From Date"), + fieldtype: "Date", + + }, + { + fieldname: "to_date", + label: __("To Date"), + fieldtype: "Date", + }, + { + fieldname: "status", + label: __("Status"), + fieldtype: "MultiSelectList", + get_data: function() { + return [ + {value: "Open", description: "Status"}, + {value: "Converted", description: "Status"}, + {value: "Quotation", description: "Status"}, + {value: "Replied", description: "Status"} + ] + } + }, + { + fieldname: "opportunity_source", + label: __("Oppoturnity Source"), + fieldtype: "Link", + options: "Lead Source", + }, + { + fieldname: "opportunity_type", + label: __("Opportunity Type"), + fieldtype: "Link", + options: "Opportunity Type", + }, + { + fieldname: "company", + label: __("Company"), + fieldtype: "Link", + options: "Company", + default: frappe.defaults.get_user_default("Company") + } + ] +}; \ No newline at end of file diff --git a/erpnext/crm/report/opportunity_summary_by_sales_stage/opportunity_summary_by_sales_stage.json b/erpnext/crm/report/opportunity_summary_by_sales_stage/opportunity_summary_by_sales_stage.json new file mode 100644 index 00000000000..3605aecacd9 --- /dev/null +++ b/erpnext/crm/report/opportunity_summary_by_sales_stage/opportunity_summary_by_sales_stage.json @@ -0,0 +1,29 @@ +{ + "add_total_row": 0, + "columns": [], + "creation": "2021-07-28 12:18:24.028737", + "disable_prepared_report": 0, + "disabled": 0, + "docstatus": 0, + "doctype": "Report", + "filters": [], + "idx": 0, + "is_standard": "Yes", + "modified": "2021-07-28 12:18:24.028737", + "modified_by": "Administrator", + "module": "CRM", + "name": "Opportunity Summary by Sales Stage", + "owner": "Administrator", + "prepared_report": 0, + "ref_doctype": "Opportunity", + "report_name": "Opportunity Summary by Sales Stage ", + "report_type": "Script Report", + "roles": [ + { + "role": "Sales User" + }, + { + "role": "Sales Manager" + } + ] +} \ No newline at end of file diff --git a/erpnext/crm/report/opportunity_summary_by_sales_stage/opportunity_summary_by_sales_stage.py b/erpnext/crm/report/opportunity_summary_by_sales_stage/opportunity_summary_by_sales_stage.py new file mode 100644 index 00000000000..f53b5bde9ee --- /dev/null +++ b/erpnext/crm/report/opportunity_summary_by_sales_stage/opportunity_summary_by_sales_stage.py @@ -0,0 +1,253 @@ +# Copyright (c) 2013, Frappe Technologies Pvt. Ltd. and contributors +# For license information, please see license.txt +import json + +import frappe +import pandas +from frappe import _ +from frappe.utils import flt + +from erpnext.setup.utils import get_exchange_rate + + +def execute(filters=None): + return OpportunitySummaryBySalesStage(filters).run() + +class OpportunitySummaryBySalesStage(object): + def __init__(self,filters=None): + self.filters = frappe._dict(filters or {}) + + def run(self): + self.get_columns() + self.get_data() + self.get_chart_data() + return self.columns, self.data, None, self.chart + + def get_columns(self): + self.columns = [] + + if self.filters.get('based_on') == 'Opportunity Owner': + self.columns.append({ + 'label': _('Opportunity Owner'), + 'fieldname': 'opportunity_owner', + 'width': 200 + }) + + if self.filters.get('based_on') == 'Source': + self.columns.append({ + 'label': _('Source'), + 'fieldname': 'source', + 'fieldtype': 'Link', + 'options': 'Lead Source', + 'width': 200 + }) + + if self.filters.get('based_on') == 'Opportunity Type': + self.columns.append({ + 'label': _('Opportunity Type'), + 'fieldname': 'opportunity_type', + 'width': 200 + }) + + self.set_sales_stage_columns() + + def set_sales_stage_columns(self): + self.sales_stage_list = frappe.db.get_list('Sales Stage', pluck='name') + + for sales_stage in self.sales_stage_list: + if self.filters.get('data_based_on') == 'Number': + self.columns.append({ + 'label': _(sales_stage), + 'fieldname': sales_stage, + 'fieldtype': 'Int', + 'width': 150 + }) + + elif self.filters.get('data_based_on') == 'Amount': + self.columns.append({ + 'label': _(sales_stage), + 'fieldname': sales_stage, + 'fieldtype': 'Currency', + 'width': 150 + }) + + def get_data(self): + self.data = [] + + based_on = { + 'Opportunity Owner': '_assign', + 'Source': 'source', + 'Opportunity Type': 'opportunity_type' + }[self.filters.get('based_on')] + + data_based_on = { + 'Number': 'count(name) as count', + 'Amount': 'opportunity_amount as amount', + }[self.filters.get('data_based_on')] + + self.get_data_query(based_on, data_based_on) + + self.get_rows() + + def get_data_query(self, based_on, data_based_on): + if self.filters.get('data_based_on') == 'Number': + group_by = '{},{}'.format('sales_stage', based_on) + self.query_result = frappe.db.get_list('Opportunity', + filters=self.get_conditions(), + fields=['sales_stage', data_based_on, based_on], + group_by=group_by + ) + + elif self.filters.get('data_based_on') == 'Amount': + self.query_result = frappe.db.get_list('Opportunity', + filters=self.get_conditions(), + fields=['sales_stage', based_on, data_based_on, 'currency'] + ) + + self.convert_to_base_currency() + + dataframe = pandas.DataFrame.from_records(self.query_result) + dataframe.replace(to_replace=[None], value='Not Assigned', inplace=True) + result = dataframe.groupby(['sales_stage', based_on], as_index=False)['amount'].sum() + + self.grouped_data = [] + + for i in range(len(result['amount'])): + self.grouped_data.append({ + 'sales_stage': result['sales_stage'][i], + based_on : result[based_on][i], + 'amount': result['amount'][i] + }) + + self.query_result = self.grouped_data + + def get_rows(self): + self.data = [] + self.get_formatted_data() + + for based_on,data in self.formatted_data.items(): + row_based_on={ + 'Opportunity Owner': 'opportunity_owner', + 'Source': 'source', + 'Opportunity Type': 'opportunity_type' + }[self.filters.get('based_on')] + + row = {row_based_on: based_on} + + for d in self.query_result: + sales_stage = d.get('sales_stage') + row[sales_stage] = data.get(sales_stage) + + self.data.append(row) + + def get_formatted_data(self): + self.formatted_data = frappe._dict() + + for d in self.query_result: + data_based_on ={ + 'Number': 'count', + 'Amount': 'amount' + }[self.filters.get('data_based_on')] + + based_on ={ + 'Opportunity Owner': '_assign', + 'Source': 'source', + 'Opportunity Type': 'opportunity_type' + }[self.filters.get('based_on')] + + if self.filters.get('based_on') == 'Opportunity Owner': + if d.get(based_on) == '[]' or d.get(based_on) is None or d.get(based_on) == 'Not Assigned': + assignments = ['Not Assigned'] + else: + assignments = json.loads(d.get(based_on)) + + sales_stage = d.get('sales_stage') + count = d.get(data_based_on) + + if assignments: + if len(assignments) > 1: + for assigned_to in assignments: + self.set_formatted_data_based_on_sales_stage(assigned_to, sales_stage, count) + else: + assigned_to = assignments[0] + self.set_formatted_data_based_on_sales_stage(assigned_to, sales_stage, count) + else: + value = d.get(based_on) + sales_stage = d.get('sales_stage') + count = d.get(data_based_on) + self.set_formatted_data_based_on_sales_stage(value, sales_stage, count) + + def set_formatted_data_based_on_sales_stage(self, based_on, sales_stage, count): + self.formatted_data.setdefault(based_on, frappe._dict()).setdefault(sales_stage, 0) + self.formatted_data[based_on][sales_stage] += count + + def get_conditions(self): + filters = [] + + if self.filters.get('company'): + filters.append({'company': self.filters.get('company')}) + + if self.filters.get('opportunity_type'): + filters.append({'opportunity_type': self.filters.get('opportunity_type')}) + + if self.filters.get('opportunity_source'): + filters.append({'source': self.filters.get('opportunity_source')}) + + if self.filters.get('status'): + filters.append({'status': ('in',self.filters.get('status'))}) + + if self.filters.get('from_date') and self.filters.get('to_date'): + filters.append(['transaction_date', 'between', [self.filters.get('from_date'), self.filters.get('to_date')]]) + + return filters + + def get_chart_data(self): + labels = [] + datasets = [] + values = [0] * 8 + + for sales_stage in self.sales_stage_list: + labels.append(sales_stage) + + 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]: + values[count] = values[count] + data[options] + + datasets.append({'name':options, 'values':values}) + + self.chart = { + 'data':{ + 'labels': labels, + 'datasets': datasets + }, + 'type':'line' + } + + def currency_conversion(self,from_currency,to_currency): + cacheobj = frappe.cache() + + if cacheobj.get(from_currency): + return flt(str(cacheobj.get(from_currency),'UTF-8')) + + else: + value = get_exchange_rate(from_currency,to_currency) + cacheobj.set(from_currency,value) + return flt(str(cacheobj.get(from_currency),'UTF-8')) + + def get_default_currency(self): + company = self.filters.get('company') + return frappe.db.get_value('Company', company, 'default_currency') + + def convert_to_base_currency(self): + default_currency = self.get_default_currency() + for data in self.query_result: + if data.get('currency') != default_currency: + opportunity_currency = data.get('currency') + value = self.currency_conversion(opportunity_currency,default_currency) + data['amount'] = data['amount'] * value diff --git a/erpnext/crm/report/opportunity_summary_by_sales_stage/test_opportunity_summary_by_sales_stage.py b/erpnext/crm/report/opportunity_summary_by_sales_stage/test_opportunity_summary_by_sales_stage.py new file mode 100644 index 00000000000..13859d9e0b4 --- /dev/null +++ b/erpnext/crm/report/opportunity_summary_by_sales_stage/test_opportunity_summary_by_sales_stage.py @@ -0,0 +1,94 @@ +import unittest + +import frappe + +from erpnext.crm.report.opportunity_summary_by_sales_stage.opportunity_summary_by_sales_stage import ( + execute, +) +from erpnext.crm.report.sales_pipeline_analytics.test_sales_pipeline_analytics import ( + create_company, + create_customer, + create_opportunity, +) + + +class TestOpportunitySummaryBySalesStage(unittest.TestCase): + @classmethod + def setUpClass(self): + frappe.db.delete("Opportunity") + create_company() + create_customer() + create_opportunity() + + def test_opportunity_summary_by_sales_stage(self): + self.check_for_opportunity_owner() + self.check_for_source() + self.check_for_opportunity_type() + self.check_all_filters() + + def check_for_opportunity_owner(self): + filters = { + 'based_on': "Opportunity Owner", + 'data_based_on': "Number", + 'company': "Best Test" + } + + report = execute(filters) + + expected_data = [{ + 'opportunity_owner': "Not Assigned", + 'Prospecting': 1 + }] + + self.assertEqual(expected_data, report[1]) + + def check_for_source(self): + filters = { + 'based_on': "Source", + 'data_based_on': "Number", + 'company': "Best Test" + } + + report = execute(filters) + + expected_data = [{ + 'source': 'Cold Calling', + 'Prospecting': 1 + }] + + self.assertEqual(expected_data, report[1]) + + def check_for_opportunity_type(self): + filters = { + 'based_on': "Opportunity Type", + 'data_based_on': "Number", + 'company': "Best Test" + } + + report = execute(filters) + + expected_data = [{ + 'opportunity_type': 'Sales', + 'Prospecting': 1 + }] + + self.assertEqual(expected_data, report[1]) + + def check_all_filters(self): + filters = { + 'based_on': "Opportunity Type", + 'data_based_on': "Number", + 'company': "Best Test", + 'opportunity_source': "Cold Calling", + 'opportunity_type': "Sales", + 'status': ["Open"] + } + + report = execute(filters) + + expected_data = [{ + 'opportunity_type': 'Sales', + 'Prospecting': 1 + }] + + self.assertEqual(expected_data, report[1]) \ No newline at end of file diff --git a/erpnext/crm/report/prospects_engaged_but_not_converted/prospects_engaged_but_not_converted.py b/erpnext/crm/report/prospects_engaged_but_not_converted/prospects_engaged_but_not_converted.py index 4a16f3d5396..41cb4422a59 100644 --- a/erpnext/crm/report/prospects_engaged_but_not_converted/prospects_engaged_but_not_converted.py +++ b/erpnext/crm/report/prospects_engaged_but_not_converted/prospects_engaged_but_not_converted.py @@ -1,7 +1,6 @@ # Copyright (c) 2013, Frappe Technologies Pvt. Ltd. and contributors # For license information, please see license.txt -from __future__ import unicode_literals import frappe from frappe import _ diff --git a/erpnext/healthcare/doctype/body_part_link/__init__.py b/erpnext/crm/report/sales_pipeline_analytics/__init__.py similarity index 100% rename from erpnext/healthcare/doctype/body_part_link/__init__.py rename to erpnext/crm/report/sales_pipeline_analytics/__init__.py diff --git a/erpnext/crm/report/sales_pipeline_analytics/sales_pipeline_analytics.js b/erpnext/crm/report/sales_pipeline_analytics/sales_pipeline_analytics.js new file mode 100644 index 00000000000..1426f4b6fd2 --- /dev/null +++ b/erpnext/crm/report/sales_pipeline_analytics/sales_pipeline_analytics.js @@ -0,0 +1,70 @@ +// Copyright (c) 2016, Frappe Technologies Pvt. Ltd. and contributors +// For license information, please see license.txt +/* eslint-disable */ + +frappe.query_reports["Sales Pipeline Analytics"] = { + "filters": [ + { + fieldname: "pipeline_by", + label: __("Pipeline By"), + fieldtype: "Select", + options: "Owner\nSales Stage", + default: "Owner" + }, + { + fieldname: "from_date", + label: __("From Date"), + fieldtype: "Date" + }, + { + fieldname: "to_date", + label: __("To Date"), + fieldtype: "Date" + }, + { + fieldname: "range", + label: __("Range"), + fieldtype: "Select", + options: "Monthly\nQuarterly", + default: "Monthly" + }, + { + fieldname: "assigned_to", + label: __("Assigned To"), + fieldtype: "Link", + options: "User" + }, + { + fieldname: "status", + label: __("Status"), + fieldtype: "Select", + options: "Open\nQuotation\nConverted\nReplied" + }, + { + fieldname: "based_on", + label: __("Based On"), + fieldtype: "Select", + options: "Number\nAmount", + default: "Number" + }, + { + fieldname: "company", + label: __("Company"), + fieldtype: "Link", + options: "Company", + default: frappe.defaults.get_user_default("Company") + }, + { + fieldname: "opportunity_source", + label: __("Opportunity Source"), + fieldtype: "Link", + options: "Lead Source" + }, + { + fieldname: "opportunity_type", + label: __("Opportunity Type"), + fieldtype: "Link", + options: "Opportunity Type" + }, + ] +}; diff --git a/erpnext/crm/report/sales_pipeline_analytics/sales_pipeline_analytics.json b/erpnext/crm/report/sales_pipeline_analytics/sales_pipeline_analytics.json new file mode 100644 index 00000000000..cffdddfd23f --- /dev/null +++ b/erpnext/crm/report/sales_pipeline_analytics/sales_pipeline_analytics.json @@ -0,0 +1,29 @@ +{ + "add_total_row": 0, + "columns": [], + "creation": "2021-07-01 17:29:09.530787", + "disable_prepared_report": 0, + "disabled": 0, + "docstatus": 0, + "doctype": "Report", + "filters": [], + "idx": 0, + "is_standard": "Yes", + "modified": "2021-07-01 17:45:17.612861", + "modified_by": "Administrator", + "module": "CRM", + "name": "Sales Pipeline Analytics", + "owner": "Administrator", + "prepared_report": 0, + "ref_doctype": "Opportunity", + "report_name": "Sales Pipeline Analytics", + "report_type": "Script Report", + "roles": [ + { + "role": "Sales User" + }, + { + "role": "Sales Manager" + } + ] +} \ No newline at end of file diff --git a/erpnext/crm/report/sales_pipeline_analytics/sales_pipeline_analytics.py b/erpnext/crm/report/sales_pipeline_analytics/sales_pipeline_analytics.py new file mode 100644 index 00000000000..1c7846b120d --- /dev/null +++ b/erpnext/crm/report/sales_pipeline_analytics/sales_pipeline_analytics.py @@ -0,0 +1,332 @@ +# Copyright (c) 2013, Frappe Technologies Pvt. Ltd. and contributors +# For license information, please see license.txt + +import json +from datetime import date + +import frappe +import pandas +from dateutil.relativedelta import relativedelta +from frappe import _ +from frappe.utils import cint, flt + +from erpnext.setup.utils import get_exchange_rate + + +def execute(filters=None): + return SalesPipelineAnalytics(filters).run() + +class SalesPipelineAnalytics(object): + def __init__(self, filters=None): + self.filters = frappe._dict(filters or {}) + + def run(self): + self.get_columns() + self.get_data() + self.get_chart_data() + + return self.columns, self.data, None, self.chart + + def get_columns(self): + self.columns = [] + + self.set_range_columns() + self.set_pipeline_based_on_column() + + def set_range_columns(self): + based_on = { + 'Number': 'Int', + 'Amount': 'Currency' + }[self.filters.get('based_on')] + + if self.filters.get('range') == 'Monthly': + month_list = self.get_month_list() + + for month in month_list: + self.columns.append({ + 'fieldname': month, + 'fieldtype': based_on, + 'label': month, + 'width': 200 + }) + + elif self.filters.get('range') == 'Quarterly': + for quarter in range(1, 5): + self.columns.append({ + 'fieldname': f'Q{quarter}', + 'fieldtype': based_on, + 'label': f'Q{quarter}', + 'width': 200 + }) + + def set_pipeline_based_on_column(self): + if self.filters.get('pipeline_by') == 'Owner': + self.columns.insert(0, { + 'fieldname': 'opportunity_owner', + 'label': _('Opportunity Owner'), + 'width': 200 + }) + + elif self.filters.get('pipeline_by') == 'Sales Stage': + self.columns.insert(0, { + 'fieldname': 'sales_stage', + 'label': _('Sales Stage'), + 'width': 200 + }) + + def get_fields(self): + self.based_on ={ + 'Owner': '_assign as opportunity_owner', + 'Sales Stage': 'sales_stage' + }[self.filters.get('pipeline_by')] + + self.data_based_on ={ + 'Number': 'count(name) as count', + 'Amount': 'opportunity_amount as amount' + }[self.filters.get('based_on')] + + self.group_by_based_on = { + 'Owner': '_assign', + 'Sales Stage': 'sales_stage' + }[self.filters.get('pipeline_by')] + + self.group_by_period = { + 'Monthly': 'month(expected_closing)', + 'Quarterly': 'QUARTER(expected_closing)' + }[self.filters.get('range')] + + self.pipeline_by = { + 'Owner': 'opportunity_owner', + 'Sales Stage': 'sales_stage' + }[self.filters.get('pipeline_by')] + + self.duration = { + 'Monthly': 'monthname(expected_closing) as month', + 'Quarterly': 'QUARTER(expected_closing) as quarter' + }[self.filters.get('range')] + + self.period_by = { + 'Monthly': 'month', + 'Quarterly': 'quarter' + }[self.filters.get('range')] + + def get_data(self): + self.get_fields() + + if self.filters.get('based_on') == 'Number': + self.query_result = frappe.db.get_list('Opportunity', + filters=self.get_conditions(), + fields=[self.based_on, self.data_based_on, self.duration], + group_by='{},{}'.format(self.group_by_based_on, self.group_by_period), + order_by=self.group_by_period + ) + + if self.filters.get('based_on') == 'Amount': + self.query_result = frappe.db.get_list('Opportunity', + filters=self.get_conditions(), + fields=[self.based_on, self.data_based_on, self.duration, 'currency'] + ) + + self.convert_to_base_currency() + + dataframe = pandas.DataFrame.from_records(self.query_result) + dataframe.replace(to_replace=[None], value='Not Assigned', inplace=True) + result = dataframe.groupby([self.pipeline_by, self.period_by], as_index=False)['amount'].sum() + + self.grouped_data = [] + + for i in range(len(result['amount'])): + self.grouped_data.append({ + self.pipeline_by : result[self.pipeline_by][i], + self.period_by : result[self.period_by][i], + 'amount': result['amount'][i] + }) + + self.query_result = self.grouped_data + + self.get_periodic_data() + self.append_data(self.pipeline_by, self.period_by) + + def get_conditions(self): + conditions = [] + + if self.filters.get('opportunity_source'): + conditions.append({'source': self.filters.get('opportunity_source')}) + + if self.filters.get('opportunity_type'): + conditions.append({'opportunity_type': self.filters.get('opportunity_type')}) + + if self.filters.get('status'): + conditions.append({'status': self.filters.get('status')}) + + if self.filters.get('company'): + conditions.append({'company': self.filters.get('company')}) + + if self.filters.get('from_date') and self.filters.get('to_date'): + conditions.append(['expected_closing', 'between', + [self.filters.get('from_date'), self.filters.get('to_date')]]) + + return conditions + + def get_chart_data(self): + labels = [] + datasets = [] + + self.append_to_dataset(datasets) + + for column in self.columns: + if column['fieldname'] != 'opportunity_owner' and column['fieldname'] != 'sales_stage': + labels.append(column['fieldname']) + + self.chart = { + 'data':{ + 'labels': labels, + 'datasets': datasets + }, + 'type':'line' + } + + return self.chart + + def get_periodic_data(self): + self.periodic_data = frappe._dict() + + based_on = { + 'Number': 'count', + 'Amount': 'amount' + }[self.filters.get('based_on')] + + pipeline_by = { + 'Owner': 'opportunity_owner', + 'Sales Stage': 'sales_stage' + }[self.filters.get('pipeline_by')] + + frequency = { + 'Monthly': 'month', + 'Quarterly': 'quarter' + }[self.filters.get('range')] + + for info in self.query_result: + if self.filters.get('range') == 'Monthly': + period = info.get(frequency) + if self.filters.get('range') == 'Quarterly': + period = f'Q{cint(info.get("quarter"))}' + + value = info.get(pipeline_by) + count_or_amount = info.get(based_on) + + if self.filters.get('pipeline_by') == 'Owner': + if value == 'Not Assigned' or value == '[]' or value is None: + assigned_to = ['Not Assigned'] + else: + assigned_to = json.loads(value) + self.check_for_assigned_to(period, value, count_or_amount, assigned_to, info) + + else: + self.set_formatted_data(period, value, count_or_amount, None) + + def set_formatted_data(self, period, value, count_or_amount, assigned_to): + if assigned_to: + if len(assigned_to) > 1: + if self.filters.get('assigned_to'): + for user in assigned_to: + if self.filters.get('assigned_to') == user: + value = user + self.periodic_data.setdefault(value, frappe._dict()).setdefault(period, 0) + self.periodic_data[value][period] += count_or_amount + else: + for user in assigned_to: + value = user + self.periodic_data.setdefault(value, frappe._dict()).setdefault(period, 0) + self.periodic_data[value][period] += count_or_amount + else: + value = assigned_to[0] + self.periodic_data.setdefault(value, frappe._dict()).setdefault(period, 0) + self.periodic_data[value][period] += count_or_amount + + else: + self.periodic_data.setdefault(value, frappe._dict()).setdefault(period, 0) + self.periodic_data[value][period] += count_or_amount + + def check_for_assigned_to(self, period, value, count_or_amount, assigned_to, info): + if self.filters.get('assigned_to'): + for data in json.loads(info.get('opportunity_owner')): + if data == self.filters.get('assigned_to'): + self.set_formatted_data(period, data, count_or_amount, assigned_to) + else: + self.set_formatted_data(period, value, count_or_amount, assigned_to) + + def get_month_list(self): + month_list= [] + current_date = date.today() + month_number = date.today().month + + for month in range(month_number,13): + month_list.append(current_date.strftime('%B')) + current_date = current_date + relativedelta(months=1) + + return month_list + + def append_to_dataset(self, datasets): + range_by = { + 'Monthly': 'month', + 'Quarterly': 'quarter' + }[self.filters.get('range')] + + based_on = { + 'Amount': 'amount', + 'Number': 'count' + }[self.filters.get('based_on')] + + if self.filters.get('range') == 'Quarterly': + frequency_list = [1,2,3,4] + count = [0] * 4 + + if self.filters.get('range') == 'Monthly': + frequency_list = self.get_month_list() + count = [0] * 12 + + for info in self.query_result: + for i in range(len(frequency_list)): + if info[range_by] == frequency_list[i]: + count[i] = count[i] + info[based_on] + datasets.append({'name': based_on, 'values': count}) + + def append_data(self, pipeline_by, period_by): + self.data = [] + for pipeline,period_data in self.periodic_data.items(): + row = {pipeline_by : pipeline} + for info in self.query_result: + if self.filters.get('range') == 'Monthly': + period = info.get(period_by) + + if self.filters.get('range') == 'Quarterly': + period = f'Q{cint(info.get(period_by))}' + + count = period_data.get(period,0.0) + row[period] = count + + self.data.append(row) + + def get_default_currency(self): + company = self.filters.get('company') + return frappe.db.get_value('Company',company,['default_currency']) + + def get_currency_rate(self, from_currency, to_currency): + cacheobj = frappe.cache() + + if cacheobj.get(from_currency): + return flt(str(cacheobj.get(from_currency),'UTF-8')) + + else: + value = get_exchange_rate(from_currency, to_currency) + cacheobj.set(from_currency, value) + return flt(str(cacheobj.get(from_currency),'UTF-8')) + + def convert_to_base_currency(self): + default_currency = self.get_default_currency() + for data in self.query_result: + if data.get('currency') != default_currency: + opportunity_currency = data.get('currency') + value = self.get_currency_rate(opportunity_currency,default_currency) + data['amount'] = data['amount'] * value diff --git a/erpnext/crm/report/sales_pipeline_analytics/test_sales_pipeline_analytics.py b/erpnext/crm/report/sales_pipeline_analytics/test_sales_pipeline_analytics.py new file mode 100644 index 00000000000..24c3839d2d9 --- /dev/null +++ b/erpnext/crm/report/sales_pipeline_analytics/test_sales_pipeline_analytics.py @@ -0,0 +1,238 @@ +import unittest + +import frappe + +from erpnext.crm.report.sales_pipeline_analytics.sales_pipeline_analytics import execute + + +class TestSalesPipelineAnalytics(unittest.TestCase): + @classmethod + def setUpClass(self): + frappe.db.delete("Opportunity") + create_company() + create_customer() + create_opportunity() + + def test_sales_pipeline_analytics(self): + self.check_for_monthly_and_number() + self.check_for_monthly_and_amount() + self.check_for_quarterly_and_number() + self.check_for_quarterly_and_amount() + self.check_for_all_filters() + + def check_for_monthly_and_number(self): + filters = { + 'pipeline_by':"Owner", + 'range':"Monthly", + 'based_on':"Number", + 'status':"Open", + 'opportunity_type':"Sales", + 'company':"Best Test" + } + + report = execute(filters) + + expected_data = [ + { + 'opportunity_owner':'Not Assigned', + 'August':1 + } + ] + + self.assertEqual(expected_data,report[1]) + + filters = { + 'pipeline_by':"Sales Stage", + 'range':"Monthly", + 'based_on':"Number", + 'status':"Open", + 'opportunity_type':"Sales", + 'company':"Best Test" + } + + report = execute(filters) + + expected_data = [ + { + 'sales_stage':'Prospecting', + 'August':1 + } + ] + + self.assertEqual(expected_data,report[1]) + + def check_for_monthly_and_amount(self): + filters = { + 'pipeline_by':"Owner", + 'range':"Monthly", + 'based_on':"Amount", + 'status':"Open", + 'opportunity_type':"Sales", + 'company':"Best Test" + } + + report = execute(filters) + + expected_data = [ + { + 'opportunity_owner':'Not Assigned', + 'August':150000 + } + ] + + self.assertEqual(expected_data,report[1]) + + filters = { + 'pipeline_by':"Sales Stage", + 'range':"Monthly", + 'based_on':"Amount", + 'status':"Open", + 'opportunity_type':"Sales", + 'company':"Best Test" + } + + report = execute(filters) + + expected_data = [ + { + 'sales_stage':'Prospecting', + 'August':150000 + } + ] + + self.assertEqual(expected_data,report[1]) + + def check_for_quarterly_and_number(self): + filters = { + 'pipeline_by':"Owner", + 'range':"Quarterly", + 'based_on':"Number", + 'status':"Open", + 'opportunity_type':"Sales", + 'company':"Best Test" + } + + report = execute(filters) + + expected_data = [ + { + 'opportunity_owner':'Not Assigned', + 'Q3':1 + } + ] + + self.assertEqual(expected_data,report[1]) + + filters = { + 'pipeline_by':"Sales Stage", + 'range':"Quarterly", + 'based_on':"Number", + 'status':"Open", + 'opportunity_type':"Sales", + 'company':"Best Test" + } + + report = execute(filters) + + expected_data = [ + { + 'sales_stage':'Prospecting', + 'Q3':1 + } + ] + + self.assertEqual(expected_data,report[1]) + + def check_for_quarterly_and_amount(self): + filters = { + 'pipeline_by':"Owner", + 'range':"Quarterly", + 'based_on':"Amount", + 'status':"Open", + 'opportunity_type':"Sales", + 'company':"Best Test" + } + + report = execute(filters) + + expected_data = [ + { + 'opportunity_owner':'Not Assigned', + 'Q3':150000 + } + ] + + self.assertEqual(expected_data,report[1]) + + filters = { + 'pipeline_by':"Sales Stage", + 'range':"Quarterly", + 'based_on':"Amount", + 'status':"Open", + 'opportunity_type':"Sales", + 'company':"Best Test" + } + + report = execute(filters) + + expected_data = [ + { + 'sales_stage':'Prospecting', + 'Q3':150000 + } + ] + + self.assertEqual(expected_data,report[1]) + + def check_for_all_filters(self): + filters = { + 'pipeline_by':"Owner", + 'range':"Monthly", + 'based_on':"Number", + 'status':"Open", + 'opportunity_type':"Sales", + 'company':"Best Test", + 'opportunity_source':'Cold Calling', + 'from_date': '2021-08-01', + 'to_date':'2021-08-31' + } + + report = execute(filters) + + expected_data = [ + { + 'opportunity_owner':'Not Assigned', + 'August': 1 + } + ] + + self.assertEqual(expected_data,report[1]) + +def create_company(): + doc = frappe.db.exists('Company','Best Test') + if not doc: + doc = frappe.new_doc('Company') + doc.company_name = 'Best Test' + doc.default_currency = "INR" + doc.insert() + +def create_customer(): + doc = frappe.db.exists("Customer","_Test NC") + if not doc: + doc = frappe.new_doc("Customer") + doc.customer_name = '_Test NC' + doc.insert() + +def create_opportunity(): + doc = frappe.db.exists({"doctype":"Opportunity","party_name":"_Test NC"}) + if not doc: + doc = frappe.new_doc("Opportunity") + doc.opportunity_from = "Customer" + customer_name = frappe.db.get_value("Customer",{"customer_name":'_Test NC'},['customer_name']) + doc.party_name = customer_name + doc.opportunity_amount = 150000 + doc.source = "Cold Calling" + doc.currency = "INR" + doc.expected_closing = "2021-08-31" + doc.company = 'Best Test' + doc.insert() \ No newline at end of file diff --git a/erpnext/crm/workspace/crm/crm.json b/erpnext/crm/workspace/crm/crm.json index c363395452b..5a63dc18d05 100644 --- a/erpnext/crm/workspace/crm/crm.json +++ b/erpnext/crm/workspace/crm/crm.json @@ -1,5 +1,4 @@ { - "category": "", "charts": [ { "chart_name": "Territory Wise Sales" @@ -7,18 +6,12 @@ ], "content": "[{\"type\": \"onboarding\", \"data\": {\"onboarding_name\":\"CRM\", \"col\": 12}}, {\"type\": \"chart\", \"data\": {\"chart_name\": null, \"col\": 12}}, {\"type\": \"spacer\", \"data\": {\"col\": 12}}, {\"type\": \"header\", \"data\": {\"text\": \"Your Shortcuts\", \"level\": 4, \"col\": 12}}, {\"type\": \"shortcut\", \"data\": {\"shortcut_name\": \"Lead\", \"col\": 4}}, {\"type\": \"shortcut\", \"data\": {\"shortcut_name\": \"Opportunity\", \"col\": 4}}, {\"type\": \"shortcut\", \"data\": {\"shortcut_name\": \"Customer\", \"col\": 4}}, {\"type\": \"shortcut\", \"data\": {\"shortcut_name\": \"Sales Analytics\", \"col\": 4}}, {\"type\": \"shortcut\", \"data\": {\"shortcut_name\": \"Dashboard\", \"col\": 4}}, {\"type\": \"spacer\", \"data\": {\"col\": 12}}, {\"type\": \"header\", \"data\": {\"text\": \"Reports & Masters\", \"level\": 4, \"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}}]", "creation": "2020-01-23 14:48:30.183272", - "developer_mode_only": 0, - "disable_user_customization": 0, "docstatus": 0, "doctype": "Workspace", - "extends": "", - "extends_another_page": 0, "for_user": "", "hide_custom": 0, "icon": "crm", "idx": 0, - "is_default": 0, - "is_standard": 0, "label": "CRM", "links": [ { @@ -147,6 +140,24 @@ "onboard": 1, "type": "Link" }, + { + "hidden": 0, + "is_query_report": 1, + "label": "Sales Pipeline Analytics", + "link_to": "Sales Pipeline Analytics", + "link_type": "Report", + "onboard": 0, + "type": "Link" + }, + { + "hidden": 0, + "is_query_report": 1, + "label": "Opportunity Summary by Sales Stage", + "link_to": "Opportunity Summary by Sales Stage", + "link_type": "Report", + "onboard": 0, + "type": "Link" + }, { "dependencies": "", "hidden": 0, @@ -403,15 +414,12 @@ "type": "Link" } ], - "modified": "2021-08-05 12:15:56.913091", + "modified": "2021-08-20 12:15:56.913092", "modified_by": "Administrator", "module": "CRM", "name": "CRM", - "onboarding": "CRM", "owner": "Administrator", "parent_page": "", - "pin_to_bottom": 0, - "pin_to_top": 0, "public": 1, "restrict_to_domain": "", "roles": [], diff --git a/erpnext/demo/data/drug_list.json b/erpnext/demo/data/drug_list.json index e91c30d199a..3069042843a 100644 --- a/erpnext/demo/data/drug_list.json +++ b/erpnext/demo/data/drug_list.json @@ -60,7 +60,6 @@ "standard_rate": 0.0, "stock_uom": "Nos", "supplier_items": [], - "synced_with_hub": 0, "taxes": [], "thumbnail": null, "tolerance": 0.0, @@ -144,7 +143,6 @@ "standard_rate": 0.0, "stock_uom": "Nos", "supplier_items": [], - "synced_with_hub": 0, "taxes": [], "thumbnail": null, "tolerance": 0.0, @@ -226,7 +224,6 @@ "standard_rate": 0.0, "stock_uom": "Nos", "supplier_items": [], - "synced_with_hub": 0, "taxes": [], "thumbnail": null, "tolerance": 0.0, @@ -308,7 +305,6 @@ "standard_rate": 0.0, "stock_uom": "Nos", "supplier_items": [], - "synced_with_hub": 0, "taxes": [], "thumbnail": null, "tolerance": 0.0, @@ -390,7 +386,6 @@ "standard_rate": 0.0, "stock_uom": "Nos", "supplier_items": [], - "synced_with_hub": 0, "taxes": [], "thumbnail": null, "tolerance": 0.0, @@ -472,7 +467,6 @@ "standard_rate": 0.0, "stock_uom": "Nos", "supplier_items": [], - "synced_with_hub": 0, "taxes": [], "thumbnail": null, "tolerance": 0.0, @@ -554,7 +548,6 @@ "standard_rate": 0.0, "stock_uom": "Nos", "supplier_items": [], - "synced_with_hub": 0, "taxes": [], "thumbnail": null, "tolerance": 0.0, @@ -636,7 +629,6 @@ "standard_rate": 0.0, "stock_uom": "Nos", "supplier_items": [], - "synced_with_hub": 0, "taxes": [], "thumbnail": null, "tolerance": 0.0, @@ -718,7 +710,6 @@ "standard_rate": 0.0, "stock_uom": "Nos", "supplier_items": [], - "synced_with_hub": 0, "taxes": [], "thumbnail": null, "tolerance": 0.0, @@ -800,7 +791,6 @@ "standard_rate": 0.0, "stock_uom": "Nos", "supplier_items": [], - "synced_with_hub": 0, "taxes": [], "thumbnail": null, "tolerance": 0.0, @@ -882,7 +872,6 @@ "standard_rate": 0.0, "stock_uom": "Nos", "supplier_items": [], - "synced_with_hub": 0, "taxes": [], "thumbnail": null, "tolerance": 0.0, @@ -964,7 +953,6 @@ "standard_rate": 0.0, "stock_uom": "Nos", "supplier_items": [], - "synced_with_hub": 0, "taxes": [], "thumbnail": null, "tolerance": 0.0, @@ -1046,7 +1034,6 @@ "standard_rate": 0.0, "stock_uom": "Nos", "supplier_items": [], - "synced_with_hub": 0, "taxes": [], "thumbnail": null, "tolerance": 0.0, @@ -1128,7 +1115,6 @@ "standard_rate": 0.0, "stock_uom": "Nos", "supplier_items": [], - "synced_with_hub": 0, "taxes": [], "thumbnail": null, "tolerance": 0.0, @@ -1210,7 +1196,6 @@ "standard_rate": 0.0, "stock_uom": "Nos", "supplier_items": [], - "synced_with_hub": 0, "taxes": [], "thumbnail": null, "tolerance": 0.0, @@ -1292,7 +1277,6 @@ "standard_rate": 0.0, "stock_uom": "Nos", "supplier_items": [], - "synced_with_hub": 0, "taxes": [], "thumbnail": null, "tolerance": 0.0, @@ -1374,7 +1358,6 @@ "standard_rate": 0.0, "stock_uom": "Nos", "supplier_items": [], - "synced_with_hub": 0, "taxes": [], "thumbnail": null, "tolerance": 0.0, @@ -1456,7 +1439,6 @@ "standard_rate": 0.0, "stock_uom": "Nos", "supplier_items": [], - "synced_with_hub": 0, "taxes": [], "thumbnail": null, "tolerance": 0.0, @@ -1538,7 +1520,6 @@ "standard_rate": 0.0, "stock_uom": "Nos", "supplier_items": [], - "synced_with_hub": 0, "taxes": [], "thumbnail": null, "tolerance": 0.0, @@ -1620,7 +1601,6 @@ "standard_rate": 0.0, "stock_uom": "Nos", "supplier_items": [], - "synced_with_hub": 0, "taxes": [], "thumbnail": null, "tolerance": 0.0, @@ -1702,7 +1682,6 @@ "standard_rate": 0.0, "stock_uom": "Nos", "supplier_items": [], - "synced_with_hub": 0, "taxes": [], "thumbnail": null, "tolerance": 0.0, @@ -1784,7 +1763,6 @@ "standard_rate": 0.0, "stock_uom": "Nos", "supplier_items": [], - "synced_with_hub": 0, "taxes": [], "thumbnail": null, "tolerance": 0.0, @@ -1866,7 +1844,6 @@ "standard_rate": 0.0, "stock_uom": "Nos", "supplier_items": [], - "synced_with_hub": 0, "taxes": [], "thumbnail": null, "tolerance": 0.0, @@ -1948,7 +1925,6 @@ "standard_rate": 0.0, "stock_uom": "Nos", "supplier_items": [], - "synced_with_hub": 0, "taxes": [], "thumbnail": null, "tolerance": 0.0, @@ -2030,7 +2006,6 @@ "standard_rate": 0.0, "stock_uom": "Nos", "supplier_items": [], - "synced_with_hub": 0, "taxes": [], "thumbnail": null, "tolerance": 0.0, @@ -2112,7 +2087,6 @@ "standard_rate": 0.0, "stock_uom": "Nos", "supplier_items": [], - "synced_with_hub": 0, "taxes": [], "thumbnail": null, "tolerance": 0.0, @@ -2194,7 +2168,6 @@ "standard_rate": 0.0, "stock_uom": "Nos", "supplier_items": [], - "synced_with_hub": 0, "taxes": [], "thumbnail": null, "tolerance": 0.0, @@ -2276,7 +2249,6 @@ "standard_rate": 0.0, "stock_uom": "Nos", "supplier_items": [], - "synced_with_hub": 0, "taxes": [], "thumbnail": null, "tolerance": 0.0, @@ -2358,7 +2330,6 @@ "standard_rate": 0.0, "stock_uom": "Nos", "supplier_items": [], - "synced_with_hub": 0, "taxes": [], "thumbnail": null, "tolerance": 0.0, @@ -2440,7 +2411,6 @@ "standard_rate": 0.0, "stock_uom": "Nos", "supplier_items": [], - "synced_with_hub": 0, "taxes": [], "thumbnail": null, "tolerance": 0.0, @@ -2522,7 +2492,6 @@ "standard_rate": 0.0, "stock_uom": "Nos", "supplier_items": [], - "synced_with_hub": 0, "taxes": [], "thumbnail": null, "tolerance": 0.0, @@ -2604,7 +2573,6 @@ "standard_rate": 0.0, "stock_uom": "Nos", "supplier_items": [], - "synced_with_hub": 0, "taxes": [], "thumbnail": null, "tolerance": 0.0, @@ -2686,7 +2654,6 @@ "standard_rate": 0.0, "stock_uom": "Nos", "supplier_items": [], - "synced_with_hub": 0, "taxes": [], "thumbnail": null, "tolerance": 0.0, @@ -2768,7 +2735,6 @@ "standard_rate": 0.0, "stock_uom": "Nos", "supplier_items": [], - "synced_with_hub": 0, "taxes": [], "thumbnail": null, "tolerance": 0.0, @@ -2850,7 +2816,6 @@ "standard_rate": 0.0, "stock_uom": "Nos", "supplier_items": [], - "synced_with_hub": 0, "taxes": [], "thumbnail": null, "tolerance": 0.0, @@ -2932,7 +2897,6 @@ "standard_rate": 0.0, "stock_uom": "Nos", "supplier_items": [], - "synced_with_hub": 0, "taxes": [], "thumbnail": null, "tolerance": 0.0, @@ -3014,7 +2978,6 @@ "standard_rate": 0.0, "stock_uom": "Nos", "supplier_items": [], - "synced_with_hub": 0, "taxes": [], "thumbnail": null, "tolerance": 0.0, @@ -3098,7 +3061,6 @@ "standard_rate": 0.0, "stock_uom": "Nos", "supplier_items": [], - "synced_with_hub": 0, "taxes": [], "thumbnail": null, "tolerance": 0.0, @@ -3180,7 +3142,6 @@ "standard_rate": 0.0, "stock_uom": "Nos", "supplier_items": [], - "synced_with_hub": 0, "taxes": [], "thumbnail": null, "tolerance": 0.0, @@ -3262,7 +3223,6 @@ "standard_rate": 0.0, "stock_uom": "Nos", "supplier_items": [], - "synced_with_hub": 0, "taxes": [], "thumbnail": null, "tolerance": 0.0, @@ -3344,7 +3304,6 @@ "standard_rate": 0.0, "stock_uom": "Nos", "supplier_items": [], - "synced_with_hub": 0, "taxes": [], "thumbnail": null, "tolerance": 0.0, @@ -3426,7 +3385,6 @@ "standard_rate": 0.0, "stock_uom": "Nos", "supplier_items": [], - "synced_with_hub": 0, "taxes": [], "thumbnail": null, "tolerance": 0.0, @@ -3508,7 +3466,6 @@ "standard_rate": 0.0, "stock_uom": "Nos", "supplier_items": [], - "synced_with_hub": 0, "taxes": [], "thumbnail": null, "tolerance": 0.0, @@ -3590,7 +3547,6 @@ "standard_rate": 0.0, "stock_uom": "Nos", "supplier_items": [], - "synced_with_hub": 0, "taxes": [], "thumbnail": null, "tolerance": 0.0, @@ -3672,7 +3628,6 @@ "standard_rate": 0.0, "stock_uom": "Nos", "supplier_items": [], - "synced_with_hub": 0, "taxes": [], "thumbnail": null, "tolerance": 0.0, @@ -3754,7 +3709,6 @@ "standard_rate": 0.0, "stock_uom": "Nos", "supplier_items": [], - "synced_with_hub": 0, "taxes": [], "thumbnail": null, "tolerance": 0.0, @@ -3836,7 +3790,6 @@ "standard_rate": 0.0, "stock_uom": "Nos", "supplier_items": [], - "synced_with_hub": 0, "taxes": [], "thumbnail": null, "tolerance": 0.0, @@ -3918,7 +3871,6 @@ "standard_rate": 0.0, "stock_uom": "Nos", "supplier_items": [], - "synced_with_hub": 0, "taxes": [], "thumbnail": null, "tolerance": 0.0, @@ -4000,7 +3952,6 @@ "standard_rate": 0.0, "stock_uom": "Nos", "supplier_items": [], - "synced_with_hub": 0, "taxes": [], "thumbnail": null, "tolerance": 0.0, @@ -4082,7 +4033,6 @@ "standard_rate": 0.0, "stock_uom": "Nos", "supplier_items": [], - "synced_with_hub": 0, "taxes": [], "thumbnail": null, "tolerance": 0.0, @@ -4164,7 +4114,6 @@ "standard_rate": 0.0, "stock_uom": "Nos", "supplier_items": [], - "synced_with_hub": 0, "taxes": [], "thumbnail": null, "tolerance": 0.0, @@ -4246,7 +4195,6 @@ "standard_rate": 0.0, "stock_uom": "Nos", "supplier_items": [], - "synced_with_hub": 0, "taxes": [], "thumbnail": null, "tolerance": 0.0, @@ -4328,7 +4276,6 @@ "standard_rate": 0.0, "stock_uom": "Nos", "supplier_items": [], - "synced_with_hub": 0, "taxes": [], "thumbnail": null, "tolerance": 0.0, @@ -4410,7 +4357,6 @@ "standard_rate": 0.0, "stock_uom": "Nos", "supplier_items": [], - "synced_with_hub": 0, "taxes": [], "thumbnail": null, "tolerance": 0.0, @@ -4492,7 +4438,6 @@ "standard_rate": 0.0, "stock_uom": "Nos", "supplier_items": [], - "synced_with_hub": 0, "taxes": [], "thumbnail": null, "tolerance": 0.0, @@ -4574,7 +4519,6 @@ "standard_rate": 0.0, "stock_uom": "Nos", "supplier_items": [], - "synced_with_hub": 0, "taxes": [], "thumbnail": null, "tolerance": 0.0, @@ -4656,7 +4600,6 @@ "standard_rate": 0.0, "stock_uom": "Nos", "supplier_items": [], - "synced_with_hub": 0, "taxes": [], "thumbnail": null, "tolerance": 0.0, @@ -4738,7 +4681,6 @@ "standard_rate": 0.0, "stock_uom": "Nos", "supplier_items": [], - "synced_with_hub": 0, "taxes": [], "thumbnail": null, "tolerance": 0.0, @@ -4820,7 +4762,6 @@ "standard_rate": 0.0, "stock_uom": "Nos", "supplier_items": [], - "synced_with_hub": 0, "taxes": [], "thumbnail": null, "tolerance": 0.0, @@ -4902,7 +4843,6 @@ "standard_rate": 0.0, "stock_uom": "Nos", "supplier_items": [], - "synced_with_hub": 0, "taxes": [], "thumbnail": null, "tolerance": 0.0, @@ -4984,7 +4924,6 @@ "standard_rate": 0.0, "stock_uom": "Nos", "supplier_items": [], - "synced_with_hub": 0, "taxes": [], "thumbnail": null, "tolerance": 0.0, @@ -5066,7 +5005,6 @@ "standard_rate": 0.0, "stock_uom": "Nos", "supplier_items": [], - "synced_with_hub": 0, "taxes": [], "thumbnail": null, "tolerance": 0.0, @@ -5148,7 +5086,6 @@ "standard_rate": 0.0, "stock_uom": "Nos", "supplier_items": [], - "synced_with_hub": 0, "taxes": [], "thumbnail": null, "tolerance": 0.0, diff --git a/erpnext/demo/demo.py b/erpnext/demo/demo.py index 5be24206ca0..4a18a99f41f 100644 --- a/erpnext/demo/demo.py +++ b/erpnext/demo/demo.py @@ -1,12 +1,10 @@ -from __future__ import unicode_literals - import sys import frappe import frappe.utils import erpnext -from erpnext.demo.setup import education, healthcare, manufacture, retail, setup_data +from erpnext.demo.setup import education, manufacture, retail, setup_data from erpnext.demo.user import accounts from erpnext.demo.user import education as edu from erpnext.demo.user import fixed_asset, hr, manufacturing, projects, purchase, sales, stock @@ -38,8 +36,6 @@ def make(domain='Manufacturing', days=100): retail.setup_data() elif domain== 'Education': education.setup_data() - elif domain== 'Healthcare': - healthcare.setup_data() site = frappe.local.site frappe.destroy() diff --git a/erpnext/demo/domains.py b/erpnext/demo/domains.py index b1db7b57b17..5fa181dfa4c 100644 --- a/erpnext/demo/domains.py +++ b/erpnext/demo/domains.py @@ -1,5 +1,3 @@ -from __future__ import unicode_literals - data = { 'Manufacturing': { 'company_name': 'Wind Power LLC' @@ -16,9 +14,6 @@ data = { 'Education': { 'company_name': 'Whitmore College' }, - 'Healthcare': { - 'company_name': 'ABC Hospital Ltd.' - }, 'Agriculture': { 'company_name': 'Schrute Farms' }, diff --git a/erpnext/demo/setup/education.py b/erpnext/demo/setup/education.py index 304bc3d2c3c..eb833f4e0c0 100644 --- a/erpnext/demo/setup/education.py +++ b/erpnext/demo/setup/education.py @@ -1,6 +1,5 @@ # Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors # License: GNU General Public License v3. See license.txt -from __future__ import unicode_literals import json import random diff --git a/erpnext/demo/setup/healthcare.py b/erpnext/demo/setup/healthcare.py deleted file mode 100644 index 5d5707f6470..00000000000 --- a/erpnext/demo/setup/healthcare.py +++ /dev/null @@ -1,171 +0,0 @@ -# Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors -# License: GNU General Public License v3. See license.txt -from __future__ import unicode_literals - -import datetime -import json - -import frappe -from frappe.utils import getdate -from frappe.utils.make_random import get_random - -from erpnext.demo.setup.setup_data import import_json -from erpnext.healthcare.doctype.lab_test.lab_test import create_test_from_template - - -def setup_data(): - frappe.flags.mute_emails = True - make_masters() - make_patient() - make_lab_test() - make_consulation() - make_appointment() - consulation_on_appointment() - lab_test_on_encounter() - frappe.db.commit() - frappe.clear_cache() - -def make_masters(): - import_json("Healthcare Practitioner") - import_drug() - frappe.db.commit() - -def make_patient(): - file_path = get_json_path("Patient") - with open(file_path, "r") as open_file: - patient_data = json.loads(open_file.read()) - count = 1 - - for d in enumerate(patient_data): - patient = frappe.new_doc("Patient") - patient.patient_name = d[1]['patient_name'].title() - patient.sex = d[1]['gender'] - patient.blood_group = "A Positive" - patient.date_of_birth = datetime.datetime(1990, 3, 25) - patient.email_id = d[1]['patient_name'] + "_" + patient.date_of_birth.strftime('%m/%d/%Y') + "@example.com" - if count <5: - patient.insert() - frappe.db.commit() - count+=1 - -def make_appointment(): - i = 1 - while i <= 4: - practitioner = get_random("Healthcare Practitioner") - department = frappe.get_value("Healthcare Practitioner", practitioner, "department") - patient = get_random("Patient") - patient_sex = frappe.get_value("Patient", patient, "sex") - appointment = frappe.new_doc("Patient Appointment") - startDate = datetime.datetime.now() - for x in random_date(startDate,0): - appointment_datetime = x - appointment.appointment_datetime = appointment_datetime - appointment.appointment_time = appointment_datetime - appointment.appointment_date = appointment_datetime - appointment.patient = patient - appointment.patient_sex = patient_sex - appointment.practitioner = practitioner - appointment.department = department - appointment.save(ignore_permissions = True) - i += 1 - -def make_consulation(): - for i in range(3): - practitioner = get_random("Healthcare Practitioner") - department = frappe.get_value("Healthcare Practitioner", practitioner, "department") - patient = get_random("Patient") - patient_sex = frappe.get_value("Patient", patient, "sex") - encounter = set_encounter(patient, patient_sex, practitioner, department, getdate(), i) - encounter.save(ignore_permissions=True) - -def consulation_on_appointment(): - for i in range(3): - appointment = get_random("Patient Appointment") - appointment = frappe.get_doc("Patient Appointment",appointment) - encounter = set_encounter(appointment.patient, appointment.patient_sex, appointment.practitioner, appointment.department, appointment.appointment_date, i) - encounter.appointment = appointment.name - encounter.save(ignore_permissions=True) - -def set_encounter(patient, patient_sex, practitioner, department, encounter_date, i): - encounter = frappe.new_doc("Patient Encounter") - encounter.patient = patient - encounter.patient_sex = patient_sex - encounter.practitioner = practitioner - encounter.visit_department = department - encounter.encounter_date = encounter_date - if i > 2 and patient_sex=='Female': - encounter.symptoms = "Having chest pains for the last week." - encounter.diagnosis = """This patient's description of dull, aching, - exertion related substernal chest pain is suggestive of ischemic - cardiac origin. Her findings of a FH of early ASCVD, hypertension, - and early surgical menopause are pertinent risk factors for development - of coronary artery disease. """ - else: - encounter = append_drug_rx(encounter) - encounter = append_test_rx(encounter) - return encounter - -def make_lab_test(): - practitioner = get_random("Healthcare Practitioner") - patient = get_random("Patient") - patient_sex = frappe.get_value("Patient", patient, "sex") - template = get_random("Lab Test Template") - set_lab_test(patient, patient_sex, practitioner, template) - -def lab_test_on_encounter(): - i = 1 - while i <= 2: - test_rx = get_random("Lab Prescription", filters={'test_created': 0}) - test_rx = frappe.get_doc("Lab Prescription", test_rx) - encounter = frappe.get_doc("Patient Encounter", test_rx.parent) - set_lab_test(encounter.patient, encounter.patient_sex, encounter.practitioner, test_rx.test_code, test_rx.name) - i += 1 - -def set_lab_test(patient, patient_sex, practitioner, template, rx=None): - lab_test = frappe.new_doc("Lab Test") - lab_test.practitioner = practitioner - lab_test.patient = patient - lab_test.patient_sex = patient_sex - lab_test.template = template - lab_test.prescription = rx - create_test_from_template(lab_test) - -def append_test_rx(encounter): - i = 1 - while i <= 2: - test_rx = encounter.append("test_prescription") - test_rx.test_code = get_random("Lab Test Template") - i += 1 - return encounter - -def append_drug_rx(encounter): - i = 1 - while i <= 3: - drug = get_random("Item", filters={"item_group":"Drug"}) - drug = frappe.get_doc("Item", drug) - drug_rx = encounter.append("drug_prescription") - drug_rx.drug_code = drug.item_code - drug_rx.drug_name = drug.item_name - drug_rx.dosage = get_random("Prescription Dosage") - drug_rx.period = get_random("Prescription Duration") - i += 1 - return encounter - -def random_date(start,l): - current = start - while l >= 0: - curr = current + datetime.timedelta(minutes=60) - yield curr - l-=1 - -def import_drug(): - frappe.flags.in_import = True - data = json.loads(open(frappe.get_app_path('erpnext', 'demo', 'data', 'drug_list.json')).read()) - for d in data: - doc = frappe.new_doc("Item") - doc.update(d) - doc.insert() - frappe.flags.in_import = False - -def get_json_path(doctype): - return frappe.get_app_path('erpnext', 'demo', 'data', frappe.scrub(doctype) + '.json') diff --git a/erpnext/demo/setup/manufacture.py b/erpnext/demo/setup/manufacture.py index 5db3519c2ce..fe1a1fb2034 100644 --- a/erpnext/demo/setup/manufacture.py +++ b/erpnext/demo/setup/manufacture.py @@ -1,11 +1,8 @@ -from __future__ import unicode_literals - import json import random import frappe from frappe.utils import add_days, nowdate -from six import iteritems from erpnext.demo.domains import data from erpnext.demo.setup.setup_data import import_json @@ -131,7 +128,7 @@ def setup_item_price(): } for price_list in ("standard_buying", "standard_selling"): - for item, rate in iteritems(locals().get(price_list)): + for item, rate in locals().get(price_list).items(): frappe.get_doc({ "doctype": "Item Price", "price_list": price_list.replace("_", " ").title(), diff --git a/erpnext/demo/setup/retail.py b/erpnext/demo/setup/retail.py index d94d2d6763a..0469264da1e 100644 --- a/erpnext/demo/setup/retail.py +++ b/erpnext/demo/setup/retail.py @@ -1,9 +1,6 @@ -from __future__ import unicode_literals - import json import frappe -from six import iteritems from erpnext.demo.domains import data @@ -53,7 +50,7 @@ def setup_item_price(): } for price_list in ("standard_buying", "standard_selling"): - for item, rate in iteritems(locals().get(price_list)): + for item, rate in locals().get(price_list).items(): frappe.get_doc({ "doctype": "Item Price", "price_list": price_list.replace("_", " ").title(), diff --git a/erpnext/demo/setup/setup_data.py b/erpnext/demo/setup/setup_data.py index 42f83a3b4e8..7137c6ef564 100644 --- a/erpnext/demo/setup/setup_data.py +++ b/erpnext/demo/setup/setup_data.py @@ -1,5 +1,3 @@ -from __future__ import print_function, unicode_literals - import json import random @@ -196,10 +194,6 @@ def setup_user_roles(domain): 'Purchase Manager', 'Projects User', 'Manufacturing User', 'Manufacturing Manager', 'Support Team') - if domain == "Healthcare": - user.add_roles('Physician', 'Healthcare Administrator', 'Laboratory User', - 'Nursing User', 'Patient') - if domain == "Education": user.add_roles('Academics User') diff --git a/erpnext/demo/user/accounts.py b/erpnext/demo/user/accounts.py index 2a248244850..273a3f92f3b 100644 --- a/erpnext/demo/user/accounts.py +++ b/erpnext/demo/user/accounts.py @@ -1,8 +1,6 @@ - # Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors # License: GNU General Public License v3. See license.txt -from __future__ import unicode_literals import random diff --git a/erpnext/demo/user/education.py b/erpnext/demo/user/education.py index adc0463a7ff..47519c16642 100644 --- a/erpnext/demo/user/education.py +++ b/erpnext/demo/user/education.py @@ -1,8 +1,6 @@ - # Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors # License: GNU General Public License v3. See license.txt -from __future__ import unicode_literals import random from datetime import timedelta diff --git a/erpnext/demo/user/fixed_asset.py b/erpnext/demo/user/fixed_asset.py index ec0e4c818ba..72cd420550a 100644 --- a/erpnext/demo/user/fixed_asset.py +++ b/erpnext/demo/user/fixed_asset.py @@ -1,8 +1,6 @@ - # Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors # License: GNU General Public License v3. See license.txt -from __future__ import unicode_literals import frappe from frappe.utils.make_random import get_random diff --git a/erpnext/demo/user/hr.py b/erpnext/demo/user/hr.py index 17d5829f908..f84a853a791 100644 --- a/erpnext/demo/user/hr.py +++ b/erpnext/demo/user/hr.py @@ -1,5 +1,3 @@ -from __future__ import unicode_literals - import datetime import random diff --git a/erpnext/demo/user/manufacturing.py b/erpnext/demo/user/manufacturing.py index 6e01f0f5a67..6b617761719 100644 --- a/erpnext/demo/user/manufacturing.py +++ b/erpnext/demo/user/manufacturing.py @@ -1,7 +1,6 @@ # Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors # License: GNU General Public License v3. See license.txt -from __future__ import unicode_literals import random from datetime import timedelta diff --git a/erpnext/demo/user/projects.py b/erpnext/demo/user/projects.py index b6b99de532d..1203be44084 100644 --- a/erpnext/demo/user/projects.py +++ b/erpnext/demo/user/projects.py @@ -1,7 +1,6 @@ # Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors # License: GNU General Public License v3. See license.txt -from __future__ import unicode_literals import frappe from frappe.utils import flt diff --git a/erpnext/demo/user/purchase.py b/erpnext/demo/user/purchase.py index ec32f973dae..61f081c26f9 100644 --- a/erpnext/demo/user/purchase.py +++ b/erpnext/demo/user/purchase.py @@ -1,7 +1,6 @@ # Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors # License: GNU General Public License v3. See license.txt -from __future__ import unicode_literals import json import random diff --git a/erpnext/demo/user/sales.py b/erpnext/demo/user/sales.py index 95494ee3242..ef6e4c42cd8 100644 --- a/erpnext/demo/user/sales.py +++ b/erpnext/demo/user/sales.py @@ -1,7 +1,6 @@ # Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors # License: GNU General Public License v3. See license.txt -from __future__ import unicode_literals import random diff --git a/erpnext/demo/user/stock.py b/erpnext/demo/user/stock.py index 188fc13f24d..de379753b3d 100644 --- a/erpnext/demo/user/stock.py +++ b/erpnext/demo/user/stock.py @@ -1,7 +1,6 @@ # Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors # License: GNU General Public License v3. See license.txt -from __future__ import print_function, unicode_literals import random diff --git a/erpnext/domains/agriculture.py b/erpnext/domains/agriculture.py index 9212d2ea719..e5414a9c090 100644 --- a/erpnext/domains/agriculture.py +++ b/erpnext/domains/agriculture.py @@ -1,5 +1,3 @@ -from __future__ import unicode_literals - data = { 'desktop_icons': [ 'Agriculture Task', diff --git a/erpnext/domains/distribution.py b/erpnext/domains/distribution.py index 3661260f9b4..020ab3b83b1 100644 --- a/erpnext/domains/distribution.py +++ b/erpnext/domains/distribution.py @@ -1,5 +1,3 @@ -from __future__ import unicode_literals - data = { 'desktop_icons': [ 'Item', diff --git a/erpnext/domains/education.py b/erpnext/domains/education.py index 870624ab3b2..11ea9b4022e 100644 --- a/erpnext/domains/education.py +++ b/erpnext/domains/education.py @@ -1,5 +1,3 @@ -from __future__ import unicode_literals - data = { 'desktop_icons': [ 'Student', diff --git a/erpnext/domains/healthcare.py b/erpnext/domains/healthcare.py deleted file mode 100644 index bbeb2c66bcf..00000000000 --- a/erpnext/domains/healthcare.py +++ /dev/null @@ -1,71 +0,0 @@ -from __future__ import unicode_literals - -data = { - 'desktop_icons': [ - 'Patient', - 'Patient Appointment', - 'Patient Encounter', - 'Lab Test', - 'Healthcare', - 'Vital Signs', - 'Clinical Procedure', - 'Inpatient Record', - 'Accounts', - 'Buying', - 'Stock', - 'HR', - 'ToDo' - ], - 'default_portal_role': 'Patient', - 'restricted_roles': [ - 'Healthcare Administrator', - 'LabTest Approver', - 'Laboratory User', - 'Nursing User', - 'Physician', - 'Patient' - ], - 'custom_fields': { - 'Sales Invoice': [ - { - 'fieldname': 'patient', 'label': 'Patient', 'fieldtype': 'Link', 'options': 'Patient', - 'insert_after': 'naming_series' - }, - { - 'fieldname': 'patient_name', 'label': 'Patient Name', 'fieldtype': 'Data', 'fetch_from': 'patient.patient_name', - 'insert_after': 'patient', 'read_only': True - }, - { - 'fieldname': 'ref_practitioner', 'label': 'Referring Practitioner', 'fieldtype': 'Link', 'options': 'Healthcare Practitioner', - 'insert_after': 'customer' - } - ], - 'Sales Invoice Item': [ - { - 'fieldname': 'reference_dt', 'label': 'Reference DocType', 'fieldtype': 'Link', 'options': 'DocType', - 'insert_after': 'edit_references' - }, - { - 'fieldname': 'reference_dn', 'label': 'Reference Name', 'fieldtype': 'Dynamic Link', 'options': 'reference_dt', - 'insert_after': 'reference_dt' - } - ], - 'Stock Entry': [ - { - 'fieldname': 'inpatient_medication_entry', 'label': 'Inpatient Medication Entry', 'fieldtype': 'Link', 'options': 'Inpatient Medication Entry', - 'insert_after': 'credit_note', 'read_only': True - } - ], - 'Stock Entry Detail': [ - { - 'fieldname': 'patient', 'label': 'Patient', 'fieldtype': 'Link', 'options': 'Patient', - 'insert_after': 'po_detail', 'read_only': True - }, - { - 'fieldname': 'inpatient_medication_entry_child', 'label': 'Inpatient Medication Entry Child', 'fieldtype': 'Data', - 'insert_after': 'patient', 'read_only': True - } - ] - }, - 'on_setup': 'erpnext.healthcare.setup.setup_healthcare' -} diff --git a/erpnext/domains/hospitality.py b/erpnext/domains/hospitality.py index 2a2d0c60ef6..09b98c288bf 100644 --- a/erpnext/domains/hospitality.py +++ b/erpnext/domains/hospitality.py @@ -1,5 +1,3 @@ -from __future__ import unicode_literals - data = { 'desktop_icons': [ 'Restaurant', diff --git a/erpnext/domains/manufacturing.py b/erpnext/domains/manufacturing.py index b9ad49e772b..96ce1945a48 100644 --- a/erpnext/domains/manufacturing.py +++ b/erpnext/domains/manufacturing.py @@ -1,5 +1,3 @@ -from __future__ import unicode_literals - data = { 'desktop_icons': [ 'Item', diff --git a/erpnext/domains/non_profit.py b/erpnext/domains/non_profit.py index 7c4f6b1f9de..d9fc5e5df01 100644 --- a/erpnext/domains/non_profit.py +++ b/erpnext/domains/non_profit.py @@ -1,5 +1,3 @@ -from __future__ import unicode_literals - data = { 'desktop_icons': [ 'Non Profit', diff --git a/erpnext/domains/retail.py b/erpnext/domains/retail.py index 73607615f33..07b2e2781ec 100644 --- a/erpnext/domains/retail.py +++ b/erpnext/domains/retail.py @@ -1,5 +1,3 @@ -from __future__ import unicode_literals - data = { 'desktop_icons': [ 'POS', diff --git a/erpnext/domains/services.py b/erpnext/domains/services.py index 89213720767..6035afbcf04 100644 --- a/erpnext/domains/services.py +++ b/erpnext/domains/services.py @@ -1,5 +1,3 @@ -from __future__ import unicode_literals - data = { 'desktop_icons': [ 'Project', diff --git a/erpnext/education/__init__.py b/erpnext/education/__init__.py index a3164b25970..56c2b29fde6 100644 --- a/erpnext/education/__init__.py +++ b/erpnext/education/__init__.py @@ -1,5 +1,3 @@ -from __future__ import unicode_literals - import frappe from frappe import _ diff --git a/erpnext/education/api.py b/erpnext/education/api.py index d2a8805c897..53d1482f951 100644 --- a/erpnext/education/api.py +++ b/erpnext/education/api.py @@ -1,8 +1,6 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2015, Frappe Technologies and contributors # For license information, please see license.txt -from __future__ import unicode_literals import json diff --git a/erpnext/education/doctype/academic_term/academic_term.py b/erpnext/education/doctype/academic_term/academic_term.py index b8e22b68c62..93861ca78af 100644 --- a/erpnext/education/doctype/academic_term/academic_term.py +++ b/erpnext/education/doctype/academic_term/academic_term.py @@ -1,8 +1,6 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2015, Frappe Technologies and contributors # For license information, please see license.txt -from __future__ import unicode_literals import frappe from frappe import _ diff --git a/erpnext/education/doctype/academic_term/academic_term_dashboard.py b/erpnext/education/doctype/academic_term/academic_term_dashboard.py index a1087b8fc42..c686b09b9e7 100644 --- a/erpnext/education/doctype/academic_term/academic_term_dashboard.py +++ b/erpnext/education/doctype/academic_term/academic_term_dashboard.py @@ -1,5 +1,3 @@ -from __future__ import unicode_literals - from frappe import _ diff --git a/erpnext/education/doctype/academic_term/test_academic_term.py b/erpnext/education/doctype/academic_term/test_academic_term.py index 6329103870f..0e39fb03d47 100644 --- a/erpnext/education/doctype/academic_term/test_academic_term.py +++ b/erpnext/education/doctype/academic_term/test_academic_term.py @@ -1,7 +1,5 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2015, Frappe Technologies and Contributors # See license.txt -from __future__ import unicode_literals import unittest diff --git a/erpnext/education/doctype/academic_year/academic_year.py b/erpnext/education/doctype/academic_year/academic_year.py index 77b67d8a5d7..e2010fb1b05 100644 --- a/erpnext/education/doctype/academic_year/academic_year.py +++ b/erpnext/education/doctype/academic_year/academic_year.py @@ -1,8 +1,6 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2015, Frappe Technologies and contributors # For license information, please see license.txt -from __future__ import unicode_literals import frappe from frappe import _ diff --git a/erpnext/education/doctype/academic_year/academic_year_dashboard.py b/erpnext/education/doctype/academic_year/academic_year_dashboard.py index 49d68c3af28..ede2411dc34 100644 --- a/erpnext/education/doctype/academic_year/academic_year_dashboard.py +++ b/erpnext/education/doctype/academic_year/academic_year_dashboard.py @@ -1,5 +1,3 @@ -from __future__ import unicode_literals - from frappe import _ diff --git a/erpnext/education/doctype/academic_year/test_academic_year.py b/erpnext/education/doctype/academic_year/test_academic_year.py index 31135c40f38..6d33fe6d7d5 100644 --- a/erpnext/education/doctype/academic_year/test_academic_year.py +++ b/erpnext/education/doctype/academic_year/test_academic_year.py @@ -1,7 +1,5 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2015, Frappe Technologies and Contributors # See license.txt -from __future__ import unicode_literals import unittest diff --git a/erpnext/education/doctype/article/article.py b/erpnext/education/doctype/article/article.py index f3c77880fc1..8f1a2e33b34 100644 --- a/erpnext/education/doctype/article/article.py +++ b/erpnext/education/doctype/article/article.py @@ -1,8 +1,6 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2018, Frappe Technologies Pvt. Ltd. and contributors # For license information, please see license.txt -from __future__ import unicode_literals import frappe from frappe.model.document import Document diff --git a/erpnext/education/doctype/article/test_article.py b/erpnext/education/doctype/article/test_article.py index cda79ad4579..2ea5c82a8b7 100644 --- a/erpnext/education/doctype/article/test_article.py +++ b/erpnext/education/doctype/article/test_article.py @@ -1,7 +1,5 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2018, Frappe Technologies Pvt. Ltd. and Contributors # See license.txt -from __future__ import unicode_literals import unittest diff --git a/erpnext/education/doctype/assessment_criteria/assessment_criteria.py b/erpnext/education/doctype/assessment_criteria/assessment_criteria.py index f8f04bf5135..58448ea9418 100644 --- a/erpnext/education/doctype/assessment_criteria/assessment_criteria.py +++ b/erpnext/education/doctype/assessment_criteria/assessment_criteria.py @@ -1,8 +1,6 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and contributors # For license information, please see license.txt -from __future__ import unicode_literals import frappe from frappe import _ diff --git a/erpnext/education/doctype/assessment_criteria/test_assessment_criteria.py b/erpnext/education/doctype/assessment_criteria/test_assessment_criteria.py index 1098d0369fb..40ba0e7816a 100644 --- a/erpnext/education/doctype/assessment_criteria/test_assessment_criteria.py +++ b/erpnext/education/doctype/assessment_criteria/test_assessment_criteria.py @@ -1,7 +1,5 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors # See license.txt -from __future__ import unicode_literals import unittest diff --git a/erpnext/education/doctype/assessment_criteria_group/assessment_criteria_group.py b/erpnext/education/doctype/assessment_criteria_group/assessment_criteria_group.py index e62c0305520..d284db595c1 100644 --- a/erpnext/education/doctype/assessment_criteria_group/assessment_criteria_group.py +++ b/erpnext/education/doctype/assessment_criteria_group/assessment_criteria_group.py @@ -1,8 +1,6 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and contributors # For license information, please see license.txt -from __future__ import unicode_literals from frappe.model.document import Document diff --git a/erpnext/education/doctype/assessment_criteria_group/test_assessment_criteria_group.py b/erpnext/education/doctype/assessment_criteria_group/test_assessment_criteria_group.py index d65f1e78d1d..ccf82bad04a 100644 --- a/erpnext/education/doctype/assessment_criteria_group/test_assessment_criteria_group.py +++ b/erpnext/education/doctype/assessment_criteria_group/test_assessment_criteria_group.py @@ -1,7 +1,5 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors # See license.txt -from __future__ import unicode_literals import unittest diff --git a/erpnext/education/doctype/assessment_group/assessment_group.py b/erpnext/education/doctype/assessment_group/assessment_group.py index 3425109331f..d606ffb41a2 100644 --- a/erpnext/education/doctype/assessment_group/assessment_group.py +++ b/erpnext/education/doctype/assessment_group/assessment_group.py @@ -1,8 +1,6 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and contributors # For license information, please see license.txt -from __future__ import unicode_literals from frappe.model.document import Document diff --git a/erpnext/education/doctype/assessment_group/assessment_group_dashboard.py b/erpnext/education/doctype/assessment_group/assessment_group_dashboard.py index 83438c0ed74..956809179bc 100644 --- a/erpnext/education/doctype/assessment_group/assessment_group_dashboard.py +++ b/erpnext/education/doctype/assessment_group/assessment_group_dashboard.py @@ -1,6 +1,5 @@ # Copyright (c) 2020, Frappe Technologies Pvt. Ltd. and Contributors # License: GNU General Public License v3. See license.txt -from __future__ import unicode_literals from frappe import _ diff --git a/erpnext/education/doctype/assessment_group/test_assessment_group.py b/erpnext/education/doctype/assessment_group/test_assessment_group.py index 822d65c9bb7..6e840aa2510 100644 --- a/erpnext/education/doctype/assessment_group/test_assessment_group.py +++ b/erpnext/education/doctype/assessment_group/test_assessment_group.py @@ -1,7 +1,5 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors # See license.txt -from __future__ import unicode_literals import unittest diff --git a/erpnext/education/doctype/assessment_plan/assessment_plan.py b/erpnext/education/doctype/assessment_plan/assessment_plan.py index 2a58a313cdd..82a28de1cb9 100644 --- a/erpnext/education/doctype/assessment_plan/assessment_plan.py +++ b/erpnext/education/doctype/assessment_plan/assessment_plan.py @@ -1,8 +1,6 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and contributors # For license information, please see license.txt -from __future__ import unicode_literals import frappe from frappe import _ diff --git a/erpnext/education/doctype/assessment_plan/assessment_plan_dashboard.py b/erpnext/education/doctype/assessment_plan/assessment_plan_dashboard.py index 672953852ed..31b9509f191 100644 --- a/erpnext/education/doctype/assessment_plan/assessment_plan_dashboard.py +++ b/erpnext/education/doctype/assessment_plan/assessment_plan_dashboard.py @@ -1,6 +1,5 @@ # Copyright (c) 2020, Frappe Technologies Pvt. Ltd. and Contributors # License: GNU General Public License v3. See license.txt -from __future__ import unicode_literals from frappe import _ diff --git a/erpnext/education/doctype/assessment_plan/test_assessment_plan.py b/erpnext/education/doctype/assessment_plan/test_assessment_plan.py index 9a6b8860358..9f55a78667b 100644 --- a/erpnext/education/doctype/assessment_plan/test_assessment_plan.py +++ b/erpnext/education/doctype/assessment_plan/test_assessment_plan.py @@ -1,7 +1,5 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors # See license.txt -from __future__ import unicode_literals import unittest diff --git a/erpnext/education/doctype/assessment_plan_criteria/assessment_plan_criteria.py b/erpnext/education/doctype/assessment_plan_criteria/assessment_plan_criteria.py index 795462d6308..2cd17d6b950 100644 --- a/erpnext/education/doctype/assessment_plan_criteria/assessment_plan_criteria.py +++ b/erpnext/education/doctype/assessment_plan_criteria/assessment_plan_criteria.py @@ -1,8 +1,6 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and contributors # For license information, please see license.txt -from __future__ import unicode_literals from frappe.model.document import Document diff --git a/erpnext/education/doctype/assessment_result/assessment_result.py b/erpnext/education/doctype/assessment_result/assessment_result.py index 01f483f8b0b..8278b9eebab 100644 --- a/erpnext/education/doctype/assessment_result/assessment_result.py +++ b/erpnext/education/doctype/assessment_result/assessment_result.py @@ -1,8 +1,6 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and contributors # For license information, please see license.txt -from __future__ import unicode_literals import frappe from frappe import _ diff --git a/erpnext/education/doctype/assessment_result/assessment_result_dashboard.py b/erpnext/education/doctype/assessment_result/assessment_result_dashboard.py index f9e2008ebc7..3b07417b88d 100644 --- a/erpnext/education/doctype/assessment_result/assessment_result_dashboard.py +++ b/erpnext/education/doctype/assessment_result/assessment_result_dashboard.py @@ -1,6 +1,5 @@ # Copyright (c) 2020, Frappe Technologies Pvt. Ltd. and Contributors # License: GNU General Public License v3. See license.txt -from __future__ import unicode_literals from frappe import _ diff --git a/erpnext/education/doctype/assessment_result/test_assessment_result.py b/erpnext/education/doctype/assessment_result/test_assessment_result.py index fa0ad1f692c..c0872dfb06d 100644 --- a/erpnext/education/doctype/assessment_result/test_assessment_result.py +++ b/erpnext/education/doctype/assessment_result/test_assessment_result.py @@ -1,7 +1,5 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors # See license.txt -from __future__ import unicode_literals import unittest diff --git a/erpnext/education/doctype/assessment_result_detail/assessment_result_detail.py b/erpnext/education/doctype/assessment_result_detail/assessment_result_detail.py index 234dff044f5..5ef11297eb2 100644 --- a/erpnext/education/doctype/assessment_result_detail/assessment_result_detail.py +++ b/erpnext/education/doctype/assessment_result_detail/assessment_result_detail.py @@ -1,8 +1,6 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and contributors # For license information, please see license.txt -from __future__ import unicode_literals from frappe.model.document import Document diff --git a/erpnext/education/doctype/assessment_result_tool/assessment_result_tool.py b/erpnext/education/doctype/assessment_result_tool/assessment_result_tool.py index 83b4f5634e9..4b953bec15f 100644 --- a/erpnext/education/doctype/assessment_result_tool/assessment_result_tool.py +++ b/erpnext/education/doctype/assessment_result_tool/assessment_result_tool.py @@ -1,8 +1,6 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and contributors # For license information, please see license.txt -from __future__ import unicode_literals from frappe.model.document import Document diff --git a/erpnext/education/doctype/assessment_result_tool/test_assessment_result_tool.py b/erpnext/education/doctype/assessment_result_tool/test_assessment_result_tool.py index bcc57220e78..49e0be08f0a 100644 --- a/erpnext/education/doctype/assessment_result_tool/test_assessment_result_tool.py +++ b/erpnext/education/doctype/assessment_result_tool/test_assessment_result_tool.py @@ -1,7 +1,5 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2017, Frappe Technologies Pvt. Ltd. and Contributors # See license.txt -from __future__ import unicode_literals import unittest diff --git a/erpnext/education/doctype/content_activity/content_activity.py b/erpnext/education/doctype/content_activity/content_activity.py index 076e2d37c00..f30cb87a9e6 100644 --- a/erpnext/education/doctype/content_activity/content_activity.py +++ b/erpnext/education/doctype/content_activity/content_activity.py @@ -1,8 +1,6 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2018, Frappe Technologies Pvt. Ltd. and contributors # For license information, please see license.txt -from __future__ import unicode_literals from frappe.model.document import Document diff --git a/erpnext/education/doctype/content_question/content_question.py b/erpnext/education/doctype/content_question/content_question.py index 9c2491697de..f52f0c85d38 100644 --- a/erpnext/education/doctype/content_question/content_question.py +++ b/erpnext/education/doctype/content_question/content_question.py @@ -1,8 +1,6 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2018, Frappe Technologies Pvt. Ltd. and contributors # For license information, please see license.txt -from __future__ import unicode_literals from frappe.model.document import Document diff --git a/erpnext/education/doctype/content_question/test_content_question.py b/erpnext/education/doctype/content_question/test_content_question.py index f6bd49bb802..63a5a96700c 100644 --- a/erpnext/education/doctype/content_question/test_content_question.py +++ b/erpnext/education/doctype/content_question/test_content_question.py @@ -1,7 +1,5 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2018, Frappe Technologies Pvt. Ltd. and Contributors # See license.txt -from __future__ import unicode_literals import unittest diff --git a/erpnext/education/doctype/course/course.py b/erpnext/education/doctype/course/course.py index 9cc373a5fe2..2d4f28226a6 100644 --- a/erpnext/education/doctype/course/course.py +++ b/erpnext/education/doctype/course/course.py @@ -1,8 +1,6 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2015, Frappe Technologies and contributors # For license information, please see license.txt -from __future__ import unicode_literals import json diff --git a/erpnext/education/doctype/course/course_dashboard.py b/erpnext/education/doctype/course/course_dashboard.py index 8eca2a13509..276830f38ae 100644 --- a/erpnext/education/doctype/course/course_dashboard.py +++ b/erpnext/education/doctype/course/course_dashboard.py @@ -1,6 +1,5 @@ # Copyright (c) 2020, Frappe Technologies Pvt. Ltd. and Contributors # License: GNU General Public License v3. See license.txt -from __future__ import unicode_literals from frappe import _ diff --git a/erpnext/education/doctype/course/test_course.py b/erpnext/education/doctype/course/test_course.py index dd43ef447c2..6381cdb11b2 100644 --- a/erpnext/education/doctype/course/test_course.py +++ b/erpnext/education/doctype/course/test_course.py @@ -1,7 +1,5 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2015, Frappe Technologies and Contributors # See license.txt -from __future__ import unicode_literals import unittest diff --git a/erpnext/education/doctype/course_activity/course_activity.py b/erpnext/education/doctype/course_activity/course_activity.py index 61b51a05a16..c1d82427dd5 100644 --- a/erpnext/education/doctype/course_activity/course_activity.py +++ b/erpnext/education/doctype/course_activity/course_activity.py @@ -1,8 +1,6 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2018, Frappe Technologies Pvt. Ltd. and contributors # For license information, please see license.txt -from __future__ import unicode_literals import frappe from frappe import _ diff --git a/erpnext/education/doctype/course_activity/test_course_activity.py b/erpnext/education/doctype/course_activity/test_course_activity.py index 778cefecab1..9514ff1bda9 100644 --- a/erpnext/education/doctype/course_activity/test_course_activity.py +++ b/erpnext/education/doctype/course_activity/test_course_activity.py @@ -1,7 +1,5 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2018, Frappe Technologies Pvt. Ltd. and Contributors # See license.txt -from __future__ import unicode_literals import unittest diff --git a/erpnext/education/doctype/course_assessment_criteria/course_assessment_criteria.py b/erpnext/education/doctype/course_assessment_criteria/course_assessment_criteria.py index df384c53143..4223741f030 100644 --- a/erpnext/education/doctype/course_assessment_criteria/course_assessment_criteria.py +++ b/erpnext/education/doctype/course_assessment_criteria/course_assessment_criteria.py @@ -1,8 +1,6 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and contributors # For license information, please see license.txt -from __future__ import unicode_literals from frappe.model.document import Document diff --git a/erpnext/education/doctype/course_content/course_content.py b/erpnext/education/doctype/course_content/course_content.py index 1dd08adbb01..abc370ecbef 100644 --- a/erpnext/education/doctype/course_content/course_content.py +++ b/erpnext/education/doctype/course_content/course_content.py @@ -1,8 +1,6 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2018, Frappe Technologies Pvt. Ltd. and contributors # For license information, please see license.txt -from __future__ import unicode_literals from frappe.model.document import Document diff --git a/erpnext/education/doctype/course_content/test_course_content.py b/erpnext/education/doctype/course_content/test_course_content.py index 320fa111f7e..49f042e8650 100644 --- a/erpnext/education/doctype/course_content/test_course_content.py +++ b/erpnext/education/doctype/course_content/test_course_content.py @@ -1,7 +1,5 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2018, Frappe Technologies Pvt. Ltd. and Contributors # See license.txt -from __future__ import unicode_literals import unittest diff --git a/erpnext/education/doctype/course_enrollment/course_enrollment.py b/erpnext/education/doctype/course_enrollment/course_enrollment.py index 21e74516f89..79212847533 100644 --- a/erpnext/education/doctype/course_enrollment/course_enrollment.py +++ b/erpnext/education/doctype/course_enrollment/course_enrollment.py @@ -1,8 +1,6 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2018, Frappe Technologies Pvt. Ltd. and contributors # For license information, please see license.txt -from __future__ import unicode_literals from functools import reduce diff --git a/erpnext/education/doctype/course_enrollment/course_enrollment_dashboard.py b/erpnext/education/doctype/course_enrollment/course_enrollment_dashboard.py index 253325c586e..14a7a8fde12 100644 --- a/erpnext/education/doctype/course_enrollment/course_enrollment_dashboard.py +++ b/erpnext/education/doctype/course_enrollment/course_enrollment_dashboard.py @@ -1,6 +1,5 @@ # Copyright (c) 2020, Frappe Technologies Pvt. Ltd. and Contributors # License: GNU General Public License v3. See license.txt -from __future__ import unicode_literals from frappe import _ diff --git a/erpnext/education/doctype/course_enrollment/test_course_enrollment.py b/erpnext/education/doctype/course_enrollment/test_course_enrollment.py index e5feb1b7f7c..e74d510e521 100644 --- a/erpnext/education/doctype/course_enrollment/test_course_enrollment.py +++ b/erpnext/education/doctype/course_enrollment/test_course_enrollment.py @@ -1,7 +1,5 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2018, Frappe Technologies Pvt. Ltd. and Contributors # See license.txt -from __future__ import unicode_literals import unittest diff --git a/erpnext/education/doctype/course_schedule/course_schedule.py b/erpnext/education/doctype/course_schedule/course_schedule.py index 38379e4c778..ffd323d3d2a 100644 --- a/erpnext/education/doctype/course_schedule/course_schedule.py +++ b/erpnext/education/doctype/course_schedule/course_schedule.py @@ -1,8 +1,7 @@ - # -*- coding: utf-8 -*- +# -*- coding: utf-8 -*- # Copyright (c) 2015, Frappe Technologies and contributors # For license information, please see license.txt -from __future__ import unicode_literals import frappe from frappe import _ diff --git a/erpnext/education/doctype/course_schedule/course_schedule_dashboard.py b/erpnext/education/doctype/course_schedule/course_schedule_dashboard.py index 12a1735f4ea..256e40b3b18 100644 --- a/erpnext/education/doctype/course_schedule/course_schedule_dashboard.py +++ b/erpnext/education/doctype/course_schedule/course_schedule_dashboard.py @@ -1,6 +1,5 @@ # Copyright (c) 2020, Frappe Technologies Pvt. Ltd. and Contributors # License: GNU General Public License v3. See license.txt -from __future__ import unicode_literals from frappe import _ diff --git a/erpnext/education/doctype/course_schedule/test_course_schedule.py b/erpnext/education/doctype/course_schedule/test_course_schedule.py index 1b45ceda484..a7324195557 100644 --- a/erpnext/education/doctype/course_schedule/test_course_schedule.py +++ b/erpnext/education/doctype/course_schedule/test_course_schedule.py @@ -1,7 +1,5 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2015, Frappe Technologies and Contributors # See license.txt -from __future__ import unicode_literals import datetime import unittest diff --git a/erpnext/education/doctype/course_scheduling_tool/course_scheduling_tool.json b/erpnext/education/doctype/course_scheduling_tool/course_scheduling_tool.json index 2926fe8af34..13dfe38eead 100644 --- a/erpnext/education/doctype/course_scheduling_tool/course_scheduling_tool.json +++ b/erpnext/education/doctype/course_scheduling_tool/course_scheduling_tool.json @@ -1,661 +1,168 @@ { - "allow_copy": 1, - "allow_guest_to_view": 0, - "allow_import": 0, - "allow_rename": 0, - "beta": 0, - "creation": "2015-09-23 15:37:38.108475", - "custom": 0, - "docstatus": 0, - "doctype": "DocType", - "document_type": "Setup", - "editable_grid": 0, - "engine": "InnoDB", + "actions": [], + "allow_copy": 1, + "creation": "2015-09-23 15:37:38.108475", + "doctype": "DocType", + "document_type": "Setup", + "engine": "InnoDB", + "field_order": [ + "student_group", + "course", + "program", + "column_break_3", + "academic_year", + "academic_term", + "section_break_6", + "instructor", + "instructor_name", + "column_break_9", + "room", + "section_break_7", + "course_start_date", + "course_end_date", + "day", + "reschedule", + "column_break_15", + "from_time", + "to_time" + ], "fields": [ { - "allow_bulk_edit": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "student_group", - "fieldtype": "Link", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 1, - "in_standard_filter": 0, - "label": "Student Group", - "length": 0, - "no_copy": 0, - "options": "Student Group", - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 1, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 - }, + "fieldname": "student_group", + "fieldtype": "Link", + "in_list_view": 1, + "label": "Student Group", + "options": "Student Group", + "reqd": 1 + }, { - "allow_bulk_edit": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "course", - "fieldtype": "Link", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 1, - "in_standard_filter": 0, - "label": "Course", - "length": 0, - "no_copy": 0, - "options": "Course", - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 1, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 - }, + "fieldname": "course", + "fieldtype": "Link", + "in_list_view": 1, + "label": "Course", + "options": "Course", + "reqd": 1 + }, { - "allow_bulk_edit": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "program", - "fieldtype": "Link", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "label": "Program", - "length": 0, - "no_copy": 0, - "options": "Program", - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 1, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 - }, + "fieldname": "program", + "fieldtype": "Link", + "label": "Program", + "options": "Program", + "read_only": 1 + }, { - "allow_bulk_edit": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "column_break_3", - "fieldtype": "Column Break", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "length": 0, - "no_copy": 0, - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 - }, + "fieldname": "column_break_3", + "fieldtype": "Column Break" + }, { - "allow_bulk_edit": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "academic_year", - "fieldtype": "Link", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "label": "Academic Year", - "length": 0, - "no_copy": 0, - "options": "Academic Year", - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 1, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 - }, + "fieldname": "academic_year", + "fieldtype": "Link", + "label": "Academic Year", + "options": "Academic Year", + "read_only": 1 + }, { - "allow_bulk_edit": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "academic_term", - "fieldtype": "Link", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "label": "Academic Term", - "length": 0, - "no_copy": 0, - "options": "Academic Term", - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 1, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 - }, + "fieldname": "academic_term", + "fieldtype": "Link", + "label": "Academic Term", + "options": "Academic Term", + "read_only": 1 + }, { - "allow_bulk_edit": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "section_break_6", - "fieldtype": "Section Break", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "length": 0, - "no_copy": 0, - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 - }, + "fieldname": "section_break_6", + "fieldtype": "Section Break" + }, { - "allow_bulk_edit": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "instructor", - "fieldtype": "Link", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 1, - "in_standard_filter": 0, - "label": "Instructor", - "length": 0, - "no_copy": 0, - "options": "Instructor", - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 1, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 - }, + "fieldname": "instructor", + "fieldtype": "Link", + "in_list_view": 1, + "label": "Instructor", + "options": "Instructor", + "reqd": 1 + }, { - "allow_bulk_edit": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, "fetch_from": "instructor.instructor_name", - "fieldname": "instructor_name", - "fieldtype": "Read Only", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "label": "Instructor Name", - "length": 0, - "no_copy": 0, - "options": "", - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 1, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 - }, + "fieldname": "instructor_name", + "fieldtype": "Read Only", + "label": "Instructor Name", + "read_only": 1 + }, { - "allow_bulk_edit": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "column_break_9", - "fieldtype": "Column Break", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "length": 0, - "no_copy": 0, - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 - }, + "fieldname": "column_break_9", + "fieldtype": "Column Break" + }, { - "allow_bulk_edit": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "room", - "fieldtype": "Link", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 1, - "in_standard_filter": 0, - "label": "Room", - "length": 0, - "no_copy": 0, - "options": "Room", - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 1, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 - }, + "fieldname": "room", + "fieldtype": "Link", + "in_list_view": 1, + "label": "Room", + "options": "Room", + "reqd": 1 + }, { - "allow_bulk_edit": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "section_break_7", - "fieldtype": "Section Break", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "length": 0, - "no_copy": 0, - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 - }, + "fieldname": "section_break_7", + "fieldtype": "Section Break" + }, { - "allow_bulk_edit": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "default": "", - "fieldname": "from_time", - "fieldtype": "Time", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "label": "From Time", - "length": 0, - "no_copy": 0, - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 1, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 - }, + "fieldname": "from_time", + "fieldtype": "Time", + "label": "From Time", + "reqd": 1 + }, { - "allow_bulk_edit": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "default": "", - "fieldname": "course_start_date", - "fieldtype": "Date", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "label": "Course Start Date", - "length": 0, - "no_copy": 0, - "options": "", - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 1, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 - }, + "fieldname": "course_start_date", + "fieldtype": "Date", + "label": "Course Start Date", + "reqd": 1 + }, { - "allow_bulk_edit": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "day", - "fieldtype": "Select", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "label": "Day", - "length": 0, - "no_copy": 0, - "options": "\nMonday\nTuesday\nWednesday\nThursday\nFriday\nSaturday\nSunday", - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 1, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 - }, + "fieldname": "day", + "fieldtype": "Select", + "label": "Day", + "options": "\nMonday\nTuesday\nWednesday\nThursday\nFriday\nSaturday\nSunday", + "reqd": 1 + }, { - "allow_bulk_edit": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "reschedule", - "fieldtype": "Check", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "label": "Reschedule", - "length": 0, - "no_copy": 0, - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 - }, + "default": "0", + "fieldname": "reschedule", + "fieldtype": "Check", + "label": "Reschedule" + }, { - "allow_bulk_edit": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "column_break_15", - "fieldtype": "Column Break", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "length": 0, - "no_copy": 0, - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 - }, + "fieldname": "column_break_15", + "fieldtype": "Column Break" + }, { - "allow_bulk_edit": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "to_time", - "fieldtype": "Time", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "label": "To TIme", - "length": 0, - "no_copy": 0, - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 1, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 - }, + "fieldname": "to_time", + "fieldtype": "Time", + "label": "To TIme", + "reqd": 1 + }, { - "allow_bulk_edit": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "default": "", - "fieldname": "course_end_date", - "fieldtype": "Date", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "label": "Course End Date", - "length": 0, - "no_copy": 0, - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 1, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 + "fieldname": "course_end_date", + "fieldtype": "Date", + "label": "Course End Date", + "reqd": 1 } - ], - "has_web_view": 0, - "hide_heading": 1, - "hide_toolbar": 1, - "idx": 0, - "image_view": 0, - "in_create": 0, - "is_submittable": 0, - "issingle": 1, - "istable": 0, - "max_attachments": 0, - "menu_index": 0, - "modified": "2018-05-16 22:43:29.363798", - "modified_by": "Administrator", - "module": "Education", - "name": "Course Scheduling Tool", - "name_case": "", - "owner": "Administrator", + ], + "hide_toolbar": 1, + "issingle": 1, + "links": [], + "modified": "2021-11-11 09:33:18.874445", + "modified_by": "Administrator", + "module": "Education", + "name": "Course Scheduling Tool", + "owner": "Administrator", "permissions": [ { - "amend": 0, - "cancel": 0, - "create": 1, - "delete": 0, - "email": 0, - "export": 0, - "if_owner": 0, - "import": 0, - "permlevel": 0, - "print": 0, - "read": 1, - "report": 0, - "role": "Academics User", - "set_user_permissions": 0, - "share": 0, - "submit": 0, + "create": 1, + "read": 1, + "role": "Academics User", "write": 1 } - ], - "quick_entry": 0, - "read_only": 0, - "read_only_onload": 0, - "restrict_to_domain": "Education", - "show_name_in_global_search": 0, - "sort_field": "modified", - "sort_order": "DESC", - "track_changes": 1, - "track_seen": 0 + ], + "restrict_to_domain": "Education", + "sort_field": "modified", + "sort_order": "DESC", + "track_changes": 1 } \ No newline at end of file diff --git a/erpnext/education/doctype/course_scheduling_tool/course_scheduling_tool.py b/erpnext/education/doctype/course_scheduling_tool/course_scheduling_tool.py index 4f7ed368211..a309e4694c8 100644 --- a/erpnext/education/doctype/course_scheduling_tool/course_scheduling_tool.py +++ b/erpnext/education/doctype/course_scheduling_tool/course_scheduling_tool.py @@ -1,8 +1,6 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and contributors # For license information, please see license.txt -from __future__ import unicode_literals import calendar diff --git a/erpnext/education/doctype/course_scheduling_tool/test_course_scheduling_tool.py b/erpnext/education/doctype/course_scheduling_tool/test_course_scheduling_tool.py index 27379b70e1c..559214bc92d 100644 --- a/erpnext/education/doctype/course_scheduling_tool/test_course_scheduling_tool.py +++ b/erpnext/education/doctype/course_scheduling_tool/test_course_scheduling_tool.py @@ -1,7 +1,5 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2017, Frappe Technologies Pvt. Ltd. and Contributors # See license.txt -from __future__ import unicode_literals import unittest diff --git a/erpnext/education/doctype/course_topic/course_topic.py b/erpnext/education/doctype/course_topic/course_topic.py index 11eb457b7c3..3c1cabf7953 100644 --- a/erpnext/education/doctype/course_topic/course_topic.py +++ b/erpnext/education/doctype/course_topic/course_topic.py @@ -1,8 +1,6 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2018, Frappe Technologies Pvt. Ltd. and contributors # For license information, please see license.txt -from __future__ import unicode_literals from frappe.model.document import Document diff --git a/erpnext/education/doctype/course_topic/test_course_topic.py b/erpnext/education/doctype/course_topic/test_course_topic.py index 0bba7f54788..a4d370c83d7 100644 --- a/erpnext/education/doctype/course_topic/test_course_topic.py +++ b/erpnext/education/doctype/course_topic/test_course_topic.py @@ -1,7 +1,5 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2018, Frappe Technologies Pvt. Ltd. and Contributors # See license.txt -from __future__ import unicode_literals import unittest diff --git a/erpnext/education/doctype/education_settings/education_settings.py b/erpnext/education/doctype/education_settings/education_settings.py index 71d13f733bd..13123be78a3 100644 --- a/erpnext/education/doctype/education_settings/education_settings.py +++ b/erpnext/education/doctype/education_settings/education_settings.py @@ -1,8 +1,6 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2017, Frappe Technologies Pvt. Ltd. and contributors # For license information, please see license.txt -from __future__ import unicode_literals import frappe import frappe.defaults diff --git a/erpnext/education/doctype/education_settings/test_education_settings.py b/erpnext/education/doctype/education_settings/test_education_settings.py index 3611cbef21a..223e8386b39 100644 --- a/erpnext/education/doctype/education_settings/test_education_settings.py +++ b/erpnext/education/doctype/education_settings/test_education_settings.py @@ -1,7 +1,5 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2017, Frappe Technologies Pvt. Ltd. and Contributors # See license.txt -from __future__ import unicode_literals import unittest diff --git a/erpnext/education/doctype/fee_category/fee_category.py b/erpnext/education/doctype/fee_category/fee_category.py index f531f8af6ee..1faa0c5e959 100644 --- a/erpnext/education/doctype/fee_category/fee_category.py +++ b/erpnext/education/doctype/fee_category/fee_category.py @@ -1,8 +1,6 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2015, Frappe Technologies and contributors # For license information, please see license.txt -from __future__ import unicode_literals from frappe.model.document import Document diff --git a/erpnext/education/doctype/fee_category/test_fee_category.py b/erpnext/education/doctype/fee_category/test_fee_category.py index 875568416f5..9e74c7de11e 100644 --- a/erpnext/education/doctype/fee_category/test_fee_category.py +++ b/erpnext/education/doctype/fee_category/test_fee_category.py @@ -1,7 +1,5 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2015, Frappe Technologies and Contributors # See license.txt -from __future__ import unicode_literals import unittest diff --git a/erpnext/education/doctype/fee_component/fee_component.py b/erpnext/education/doctype/fee_component/fee_component.py index dba39af5948..c5cf7d9331e 100644 --- a/erpnext/education/doctype/fee_component/fee_component.py +++ b/erpnext/education/doctype/fee_component/fee_component.py @@ -1,8 +1,6 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and contributors # For license information, please see license.txt -from __future__ import unicode_literals from frappe.model.document import Document diff --git a/erpnext/education/doctype/fee_schedule/fee_schedule.py b/erpnext/education/doctype/fee_schedule/fee_schedule.py index 6bf46671790..a122fe88564 100644 --- a/erpnext/education/doctype/fee_schedule/fee_schedule.py +++ b/erpnext/education/doctype/fee_schedule/fee_schedule.py @@ -1,8 +1,6 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2017, Frappe Technologies Pvt. Ltd. and contributors # For license information, please see license.txt -from __future__ import unicode_literals import frappe from frappe import _ diff --git a/erpnext/education/doctype/fee_schedule/fee_schedule_dashboard.py b/erpnext/education/doctype/fee_schedule/fee_schedule_dashboard.py index 34f870578fd..f5d1dee98b4 100644 --- a/erpnext/education/doctype/fee_schedule/fee_schedule_dashboard.py +++ b/erpnext/education/doctype/fee_schedule/fee_schedule_dashboard.py @@ -1,6 +1,5 @@ # Copyright (c) 2020, Frappe Technologies Pvt. Ltd. and Contributors # License: GNU General Public License v3. See license.txt -from __future__ import unicode_literals def get_data(): diff --git a/erpnext/education/doctype/fee_schedule/test_fee_schedule.py b/erpnext/education/doctype/fee_schedule/test_fee_schedule.py index 86b74de3421..c291aed3106 100644 --- a/erpnext/education/doctype/fee_schedule/test_fee_schedule.py +++ b/erpnext/education/doctype/fee_schedule/test_fee_schedule.py @@ -1,7 +1,5 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2017, Frappe Technologies Pvt. Ltd. and Contributors # See license.txt -from __future__ import unicode_literals import unittest diff --git a/erpnext/education/doctype/fee_schedule_program/fee_schedule_program.py b/erpnext/education/doctype/fee_schedule_program/fee_schedule_program.py index 5e9ed61ba82..ad7af3a3ab6 100644 --- a/erpnext/education/doctype/fee_schedule_program/fee_schedule_program.py +++ b/erpnext/education/doctype/fee_schedule_program/fee_schedule_program.py @@ -1,8 +1,6 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2017, Frappe Technologies Pvt. Ltd. and contributors # For license information, please see license.txt -from __future__ import unicode_literals from frappe.model.document import Document diff --git a/erpnext/education/doctype/fee_schedule_student_group/fee_schedule_student_group.py b/erpnext/education/doctype/fee_schedule_student_group/fee_schedule_student_group.py index ba30a91516f..24e54041778 100644 --- a/erpnext/education/doctype/fee_schedule_student_group/fee_schedule_student_group.py +++ b/erpnext/education/doctype/fee_schedule_student_group/fee_schedule_student_group.py @@ -1,8 +1,6 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2017, Frappe Technologies Pvt. Ltd. and contributors # For license information, please see license.txt -from __future__ import unicode_literals from frappe.model.document import Document diff --git a/erpnext/education/doctype/fee_structure/fee_structure.py b/erpnext/education/doctype/fee_structure/fee_structure.py index a6cc7019215..9090a6b9d54 100644 --- a/erpnext/education/doctype/fee_structure/fee_structure.py +++ b/erpnext/education/doctype/fee_structure/fee_structure.py @@ -1,8 +1,6 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2015, Frappe Technologies and contributors # For license information, please see license.txt -from __future__ import unicode_literals import frappe from frappe.model.document import Document diff --git a/erpnext/education/doctype/fee_structure/fee_structure_dashboard.py b/erpnext/education/doctype/fee_structure/fee_structure_dashboard.py index c053b4ea4ba..27ce06b29b3 100644 --- a/erpnext/education/doctype/fee_structure/fee_structure_dashboard.py +++ b/erpnext/education/doctype/fee_structure/fee_structure_dashboard.py @@ -1,6 +1,5 @@ # Copyright (c) 2020, Frappe Technologies Pvt. Ltd. and Contributors # License: GNU General Public License v3. See license.txt -from __future__ import unicode_literals from frappe import _ diff --git a/erpnext/education/doctype/fee_structure/test_fee_structure.py b/erpnext/education/doctype/fee_structure/test_fee_structure.py index 1311f13997e..61381a6289c 100644 --- a/erpnext/education/doctype/fee_structure/test_fee_structure.py +++ b/erpnext/education/doctype/fee_structure/test_fee_structure.py @@ -1,7 +1,5 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2015, Frappe Technologies and Contributors # See license.txt -from __future__ import unicode_literals import unittest diff --git a/erpnext/education/doctype/fees/fees.py b/erpnext/education/doctype/fees/fees.py index a5dc0dca31c..41d428d23de 100644 --- a/erpnext/education/doctype/fees/fees.py +++ b/erpnext/education/doctype/fees/fees.py @@ -1,8 +1,6 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2015, Frappe Technologies and contributors # For license information, please see license.txt -from __future__ import unicode_literals import frappe from frappe import _ diff --git a/erpnext/education/doctype/fees/test_fees.py b/erpnext/education/doctype/fees/test_fees.py index fbf7a571fe8..72f1d113962 100644 --- a/erpnext/education/doctype/fees/test_fees.py +++ b/erpnext/education/doctype/fees/test_fees.py @@ -1,7 +1,5 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2015, Frappe Technologies and Contributors # See license.txt -from __future__ import unicode_literals import unittest diff --git a/erpnext/education/doctype/grading_scale/grading_scale.py b/erpnext/education/doctype/grading_scale/grading_scale.py index ed75f31d841..c4bd1589b26 100644 --- a/erpnext/education/doctype/grading_scale/grading_scale.py +++ b/erpnext/education/doctype/grading_scale/grading_scale.py @@ -1,8 +1,6 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and contributors # For license information, please see license.txt -from __future__ import unicode_literals import frappe from frappe import _ diff --git a/erpnext/education/doctype/grading_scale/grading_scale_dashboard.py b/erpnext/education/doctype/grading_scale/grading_scale_dashboard.py index 268871a04e8..b8ae8b08a98 100644 --- a/erpnext/education/doctype/grading_scale/grading_scale_dashboard.py +++ b/erpnext/education/doctype/grading_scale/grading_scale_dashboard.py @@ -1,5 +1,3 @@ -from __future__ import unicode_literals - from frappe import _ diff --git a/erpnext/education/doctype/grading_scale/test_grading_scale.py b/erpnext/education/doctype/grading_scale/test_grading_scale.py index e5d83c20c12..3ebefda22fc 100644 --- a/erpnext/education/doctype/grading_scale/test_grading_scale.py +++ b/erpnext/education/doctype/grading_scale/test_grading_scale.py @@ -1,7 +1,5 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors # See license.txt -from __future__ import unicode_literals import unittest diff --git a/erpnext/education/doctype/grading_scale_interval/grading_scale_interval.py b/erpnext/education/doctype/grading_scale_interval/grading_scale_interval.py index 6e55aac40ba..b4101bdcc28 100644 --- a/erpnext/education/doctype/grading_scale_interval/grading_scale_interval.py +++ b/erpnext/education/doctype/grading_scale_interval/grading_scale_interval.py @@ -1,8 +1,6 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and contributors # For license information, please see license.txt -from __future__ import unicode_literals from frappe.model.document import Document diff --git a/erpnext/education/doctype/guardian/guardian.py b/erpnext/education/doctype/guardian/guardian.py index f79e1310345..aae651b8550 100644 --- a/erpnext/education/doctype/guardian/guardian.py +++ b/erpnext/education/doctype/guardian/guardian.py @@ -1,8 +1,6 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and contributors # For license information, please see license.txt -from __future__ import unicode_literals import frappe from frappe import _ diff --git a/erpnext/education/doctype/guardian/test_guardian.py b/erpnext/education/doctype/guardian/test_guardian.py index 446e2612215..f474ed5e06e 100644 --- a/erpnext/education/doctype/guardian/test_guardian.py +++ b/erpnext/education/doctype/guardian/test_guardian.py @@ -1,7 +1,5 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors # See license.txt -from __future__ import unicode_literals import unittest diff --git a/erpnext/education/doctype/guardian_interest/guardian_interest.py b/erpnext/education/doctype/guardian_interest/guardian_interest.py index 4a3040f0600..6cd1e55d831 100644 --- a/erpnext/education/doctype/guardian_interest/guardian_interest.py +++ b/erpnext/education/doctype/guardian_interest/guardian_interest.py @@ -1,8 +1,6 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and contributors # For license information, please see license.txt -from __future__ import unicode_literals from frappe.model.document import Document diff --git a/erpnext/education/doctype/guardian_student/guardian_student.py b/erpnext/education/doctype/guardian_student/guardian_student.py index 62867d89089..4c29575bee1 100644 --- a/erpnext/education/doctype/guardian_student/guardian_student.py +++ b/erpnext/education/doctype/guardian_student/guardian_student.py @@ -1,8 +1,6 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and contributors # For license information, please see license.txt -from __future__ import unicode_literals from frappe.model.document import Document diff --git a/erpnext/education/doctype/instructor/instructor.py b/erpnext/education/doctype/instructor/instructor.py index 92fb8b04b90..0076240f86f 100644 --- a/erpnext/education/doctype/instructor/instructor.py +++ b/erpnext/education/doctype/instructor/instructor.py @@ -1,8 +1,6 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2015, Frappe Technologies and contributors # For license information, please see license.txt -from __future__ import unicode_literals import frappe from frappe import _ diff --git a/erpnext/education/doctype/instructor/instructor_dashboard.py b/erpnext/education/doctype/instructor/instructor_dashboard.py index bb08a54903c..eae67acabfd 100644 --- a/erpnext/education/doctype/instructor/instructor_dashboard.py +++ b/erpnext/education/doctype/instructor/instructor_dashboard.py @@ -1,6 +1,5 @@ # Copyright (c) 2020, Frappe Technologies Pvt. Ltd. and Contributors # License: GNU General Public License v3. See license.txt -from __future__ import unicode_literals from frappe import _ diff --git a/erpnext/education/doctype/instructor/test_instructor.py b/erpnext/education/doctype/instructor/test_instructor.py index b698a20e111..4eab37ae01f 100644 --- a/erpnext/education/doctype/instructor/test_instructor.py +++ b/erpnext/education/doctype/instructor/test_instructor.py @@ -1,7 +1,5 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2015, Frappe Technologies and Contributors # See license.txt -from __future__ import unicode_literals import unittest diff --git a/erpnext/education/doctype/instructor_log/instructor_log.py b/erpnext/education/doctype/instructor_log/instructor_log.py index 68ab7a639e9..12d11ba005e 100644 --- a/erpnext/education/doctype/instructor_log/instructor_log.py +++ b/erpnext/education/doctype/instructor_log/instructor_log.py @@ -1,8 +1,6 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2017, Frappe Technologies Pvt. Ltd. and contributors # For license information, please see license.txt -from __future__ import unicode_literals from frappe.model.document import Document diff --git a/erpnext/education/doctype/options/options.py b/erpnext/education/doctype/options/options.py index a064384129b..968a7729009 100644 --- a/erpnext/education/doctype/options/options.py +++ b/erpnext/education/doctype/options/options.py @@ -1,8 +1,6 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2018, Frappe Technologies Pvt. Ltd. and contributors # For license information, please see license.txt -from __future__ import unicode_literals from frappe.model.document import Document diff --git a/erpnext/education/doctype/program/program.py b/erpnext/education/doctype/program/program.py index 7de34cf30fb..a9ce64409ab 100644 --- a/erpnext/education/doctype/program/program.py +++ b/erpnext/education/doctype/program/program.py @@ -1,8 +1,6 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2015, Frappe Technologies and contributors # For license information, please see license.txt -from __future__ import unicode_literals import frappe from frappe.model.document import Document diff --git a/erpnext/education/doctype/program/test_program.py b/erpnext/education/doctype/program/test_program.py index 3222aa6004b..cb8926bcf7e 100644 --- a/erpnext/education/doctype/program/test_program.py +++ b/erpnext/education/doctype/program/test_program.py @@ -1,7 +1,5 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2015, Frappe Technologies and Contributors # See license.txt -from __future__ import unicode_literals import unittest diff --git a/erpnext/education/doctype/program_course/program_course.py b/erpnext/education/doctype/program_course/program_course.py index d5236a109a4..dec392c42cc 100644 --- a/erpnext/education/doctype/program_course/program_course.py +++ b/erpnext/education/doctype/program_course/program_course.py @@ -1,8 +1,6 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2015, Frappe and contributors # For license information, please see license.txt -from __future__ import unicode_literals from frappe.model.document import Document diff --git a/erpnext/education/doctype/program_enrollment/program_enrollment.py b/erpnext/education/doctype/program_enrollment/program_enrollment.py index 79c5a14d8c8..a23d49267e6 100644 --- a/erpnext/education/doctype/program_enrollment/program_enrollment.py +++ b/erpnext/education/doctype/program_enrollment/program_enrollment.py @@ -1,8 +1,6 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2015, Frappe and contributors # For license information, please see license.txt -from __future__ import unicode_literals import frappe from frappe import _, msgprint diff --git a/erpnext/education/doctype/program_enrollment/program_enrollment_dashboard.py b/erpnext/education/doctype/program_enrollment/program_enrollment_dashboard.py index f829276dac9..14ed95d48cd 100644 --- a/erpnext/education/doctype/program_enrollment/program_enrollment_dashboard.py +++ b/erpnext/education/doctype/program_enrollment/program_enrollment_dashboard.py @@ -1,5 +1,3 @@ -from __future__ import unicode_literals - from frappe import _ diff --git a/erpnext/education/doctype/program_enrollment/test_program_enrollment.py b/erpnext/education/doctype/program_enrollment/test_program_enrollment.py index 65de38af2dd..dda2465eafd 100644 --- a/erpnext/education/doctype/program_enrollment/test_program_enrollment.py +++ b/erpnext/education/doctype/program_enrollment/test_program_enrollment.py @@ -1,7 +1,5 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2015, Frappe and Contributors # See license.txt -from __future__ import unicode_literals import unittest diff --git a/erpnext/education/doctype/program_enrollment_course/program_enrollment_course.py b/erpnext/education/doctype/program_enrollment_course/program_enrollment_course.py index 5c0706dbce1..8b2d82c5ee4 100644 --- a/erpnext/education/doctype/program_enrollment_course/program_enrollment_course.py +++ b/erpnext/education/doctype/program_enrollment_course/program_enrollment_course.py @@ -1,8 +1,6 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2017, Frappe Technologies Pvt. Ltd. and contributors # For license information, please see license.txt -from __future__ import unicode_literals from frappe.model.document import Document diff --git a/erpnext/education/doctype/program_enrollment_fee/program_enrollment_fee.py b/erpnext/education/doctype/program_enrollment_fee/program_enrollment_fee.py index 53bae7c1504..17d410f7b28 100644 --- a/erpnext/education/doctype/program_enrollment_fee/program_enrollment_fee.py +++ b/erpnext/education/doctype/program_enrollment_fee/program_enrollment_fee.py @@ -1,8 +1,6 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2015, Frappe and contributors # For license information, please see license.txt -from __future__ import unicode_literals from frappe.model.document import Document diff --git a/erpnext/education/doctype/program_enrollment_tool/program_enrollment_tool.py b/erpnext/education/doctype/program_enrollment_tool/program_enrollment_tool.py index 69fa66558d3..7ffa077534a 100644 --- a/erpnext/education/doctype/program_enrollment_tool/program_enrollment_tool.py +++ b/erpnext/education/doctype/program_enrollment_tool/program_enrollment_tool.py @@ -1,8 +1,6 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2015, Frappe and contributors # For license information, please see license.txt -from __future__ import unicode_literals import frappe from frappe import _ diff --git a/erpnext/education/doctype/program_enrollment_tool/test_program_enrollment_tool.py b/erpnext/education/doctype/program_enrollment_tool/test_program_enrollment_tool.py index 55734cbc94b..e806792eecd 100644 --- a/erpnext/education/doctype/program_enrollment_tool/test_program_enrollment_tool.py +++ b/erpnext/education/doctype/program_enrollment_tool/test_program_enrollment_tool.py @@ -1,7 +1,5 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2017, Frappe Technologies Pvt. Ltd. and Contributors # See license.txt -from __future__ import unicode_literals import unittest diff --git a/erpnext/education/doctype/program_enrollment_tool_student/program_enrollment_tool_student.py b/erpnext/education/doctype/program_enrollment_tool_student/program_enrollment_tool_student.py index 67653458f5f..b37e5d343eb 100644 --- a/erpnext/education/doctype/program_enrollment_tool_student/program_enrollment_tool_student.py +++ b/erpnext/education/doctype/program_enrollment_tool_student/program_enrollment_tool_student.py @@ -1,8 +1,6 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2015, Frappe and contributors # For license information, please see license.txt -from __future__ import unicode_literals from frappe.model.document import Document diff --git a/erpnext/education/doctype/program_fee/program_fee.py b/erpnext/education/doctype/program_fee/program_fee.py index 70105ee6be9..e9a0be102cd 100644 --- a/erpnext/education/doctype/program_fee/program_fee.py +++ b/erpnext/education/doctype/program_fee/program_fee.py @@ -1,8 +1,6 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2015, Frappe and contributors # For license information, please see license.txt -from __future__ import unicode_literals from frappe.model.document import Document diff --git a/erpnext/education/doctype/question/question.py b/erpnext/education/doctype/question/question.py index e74aa93ad8e..aa6cf9f38d0 100644 --- a/erpnext/education/doctype/question/question.py +++ b/erpnext/education/doctype/question/question.py @@ -1,8 +1,6 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2018, Frappe Technologies Pvt. Ltd. and contributors # For license information, please see license.txt -from __future__ import unicode_literals import frappe from frappe import _ diff --git a/erpnext/education/doctype/question/test_question.py b/erpnext/education/doctype/question/test_question.py index 1ce10c0cb83..7506d84a098 100644 --- a/erpnext/education/doctype/question/test_question.py +++ b/erpnext/education/doctype/question/test_question.py @@ -1,7 +1,5 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2018, Frappe Technologies Pvt. Ltd. and Contributors # See license.txt -from __future__ import unicode_literals import unittest diff --git a/erpnext/education/doctype/quiz/quiz.py b/erpnext/education/doctype/quiz/quiz.py index 474bea111b9..9ad7252db62 100644 --- a/erpnext/education/doctype/quiz/quiz.py +++ b/erpnext/education/doctype/quiz/quiz.py @@ -1,8 +1,6 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2018, Frappe Technologies Pvt. Ltd. and contributors # For license information, please see license.txt -from __future__ import unicode_literals import frappe from frappe import _ diff --git a/erpnext/education/doctype/quiz/test_quiz.py b/erpnext/education/doctype/quiz/test_quiz.py index 22eb23d4fda..a69a0c1d580 100644 --- a/erpnext/education/doctype/quiz/test_quiz.py +++ b/erpnext/education/doctype/quiz/test_quiz.py @@ -1,7 +1,5 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2018, Frappe Technologies Pvt. Ltd. and Contributors # See license.txt -from __future__ import unicode_literals import unittest diff --git a/erpnext/education/doctype/quiz_activity/quiz_activity.py b/erpnext/education/doctype/quiz_activity/quiz_activity.py index 0fc76032283..a67f82fe07e 100644 --- a/erpnext/education/doctype/quiz_activity/quiz_activity.py +++ b/erpnext/education/doctype/quiz_activity/quiz_activity.py @@ -1,8 +1,6 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2018, Frappe Technologies Pvt. Ltd. and contributors # For license information, please see license.txt -from __future__ import unicode_literals from frappe.model.document import Document diff --git a/erpnext/education/doctype/quiz_activity/test_quiz_activity.py b/erpnext/education/doctype/quiz_activity/test_quiz_activity.py index 44e3a3f92ba..1040c1a869c 100644 --- a/erpnext/education/doctype/quiz_activity/test_quiz_activity.py +++ b/erpnext/education/doctype/quiz_activity/test_quiz_activity.py @@ -1,7 +1,5 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2018, Frappe Technologies Pvt. Ltd. and Contributors # See license.txt -from __future__ import unicode_literals import unittest diff --git a/erpnext/education/doctype/quiz_question/quiz_question.py b/erpnext/education/doctype/quiz_question/quiz_question.py index 20cb9f7b38c..91641ebb301 100644 --- a/erpnext/education/doctype/quiz_question/quiz_question.py +++ b/erpnext/education/doctype/quiz_question/quiz_question.py @@ -1,8 +1,6 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2018, Frappe Technologies Pvt. Ltd. and contributors # For license information, please see license.txt -from __future__ import unicode_literals from frappe.model.document import Document diff --git a/erpnext/education/doctype/quiz_result/quiz_result.py b/erpnext/education/doctype/quiz_result/quiz_result.py index 059d294cff6..615281bad21 100644 --- a/erpnext/education/doctype/quiz_result/quiz_result.py +++ b/erpnext/education/doctype/quiz_result/quiz_result.py @@ -1,8 +1,6 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2018, Frappe Technologies Pvt. Ltd. and contributors # For license information, please see license.txt -from __future__ import unicode_literals from frappe.model.document import Document diff --git a/erpnext/education/doctype/quiz_result/test_quiz_result.py b/erpnext/education/doctype/quiz_result/test_quiz_result.py index 08ac4811bca..12098a77ffc 100644 --- a/erpnext/education/doctype/quiz_result/test_quiz_result.py +++ b/erpnext/education/doctype/quiz_result/test_quiz_result.py @@ -1,7 +1,5 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2018, Frappe Technologies Pvt. Ltd. and Contributors # See license.txt -from __future__ import unicode_literals import unittest diff --git a/erpnext/education/doctype/room/room.py b/erpnext/education/doctype/room/room.py index dc68a0dd0cf..a2a89805a8c 100644 --- a/erpnext/education/doctype/room/room.py +++ b/erpnext/education/doctype/room/room.py @@ -1,8 +1,6 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2015, Frappe Technologies and contributors # For license information, please see license.txt -from __future__ import unicode_literals from frappe.model.document import Document diff --git a/erpnext/education/doctype/room/room_dashboard.py b/erpnext/education/doctype/room/room_dashboard.py index 6a43b6037f8..b710722f55d 100644 --- a/erpnext/education/doctype/room/room_dashboard.py +++ b/erpnext/education/doctype/room/room_dashboard.py @@ -1,6 +1,5 @@ # Copyright (c) 2020, Frappe Technologies Pvt. Ltd. and Contributors # License: GNU General Public License v3. See license.txt -from __future__ import unicode_literals from frappe import _ diff --git a/erpnext/education/doctype/room/test_room.py b/erpnext/education/doctype/room/test_room.py index 5718d51d658..68c97c7a008 100644 --- a/erpnext/education/doctype/room/test_room.py +++ b/erpnext/education/doctype/room/test_room.py @@ -1,7 +1,5 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2015, Frappe Technologies and Contributors # See license.txt -from __future__ import unicode_literals import unittest diff --git a/erpnext/education/doctype/school_house/school_house.py b/erpnext/education/doctype/school_house/school_house.py index 2f9c5f46a80..52e05087585 100644 --- a/erpnext/education/doctype/school_house/school_house.py +++ b/erpnext/education/doctype/school_house/school_house.py @@ -1,8 +1,6 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2017, Frappe Technologies Pvt. Ltd. and contributors # For license information, please see license.txt -from __future__ import unicode_literals from frappe.model.document import Document diff --git a/erpnext/education/doctype/school_house/test_school_house.py b/erpnext/education/doctype/school_house/test_school_house.py index b58b7d49ce1..7fe12d74366 100644 --- a/erpnext/education/doctype/school_house/test_school_house.py +++ b/erpnext/education/doctype/school_house/test_school_house.py @@ -1,7 +1,5 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2017, Frappe Technologies Pvt. Ltd. and Contributors # See license.txt -from __future__ import unicode_literals import unittest diff --git a/erpnext/education/doctype/student/student.py b/erpnext/education/doctype/student/student.py index ae498ba57db..44a327777bf 100644 --- a/erpnext/education/doctype/student/student.py +++ b/erpnext/education/doctype/student/student.py @@ -1,8 +1,6 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2015, Frappe Technologies and contributors # For license information, please see license.txt -from __future__ import unicode_literals import frappe from frappe import _ @@ -138,7 +136,9 @@ class Student(Document): enrollment.submit() return enrollment - def enroll_in_course(self, course_name, program_enrollment, enrollment_date=frappe.utils.datetime.datetime.now()): + def enroll_in_course(self, course_name, program_enrollment, enrollment_date=None): + if enrollment_date is None: + enrollment_date = frappe.utils.datetime.datetime.now() try: enrollment = frappe.get_doc({ "doctype": "Course Enrollment", diff --git a/erpnext/education/doctype/student/student_dashboard.py b/erpnext/education/doctype/student/student_dashboard.py index efff2e64907..3ae772dd907 100644 --- a/erpnext/education/doctype/student/student_dashboard.py +++ b/erpnext/education/doctype/student/student_dashboard.py @@ -1,5 +1,3 @@ -from __future__ import unicode_literals - from frappe import _ diff --git a/erpnext/education/doctype/student/test_student.py b/erpnext/education/doctype/student/test_student.py index ec6abb56efb..0a85708152c 100644 --- a/erpnext/education/doctype/student/test_student.py +++ b/erpnext/education/doctype/student/test_student.py @@ -1,7 +1,5 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2015, Frappe Technologies and Contributors # See license.txt -from __future__ import unicode_literals import unittest diff --git a/erpnext/education/doctype/student_admission/student_admission.py b/erpnext/education/doctype/student_admission/student_admission.py index 67ef67b4aa2..b1fd780d8cc 100644 --- a/erpnext/education/doctype/student_admission/student_admission.py +++ b/erpnext/education/doctype/student_admission/student_admission.py @@ -1,8 +1,6 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and contributors # For license information, please see license.txt -from __future__ import unicode_literals import frappe from frappe import _ diff --git a/erpnext/education/doctype/student_admission/test_student_admission.py b/erpnext/education/doctype/student_admission/test_student_admission.py index c9cfbca14a7..03867e2ce0e 100644 --- a/erpnext/education/doctype/student_admission/test_student_admission.py +++ b/erpnext/education/doctype/student_admission/test_student_admission.py @@ -1,7 +1,5 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors # See license.txt -from __future__ import unicode_literals import unittest diff --git a/erpnext/education/doctype/student_admission_program/student_admission_program.py b/erpnext/education/doctype/student_admission_program/student_admission_program.py index 2377d2648da..eba22391480 100644 --- a/erpnext/education/doctype/student_admission_program/student_admission_program.py +++ b/erpnext/education/doctype/student_admission_program/student_admission_program.py @@ -1,8 +1,6 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2017, Frappe Technologies Pvt. Ltd. and contributors # For license information, please see license.txt -from __future__ import unicode_literals from frappe.model.document import Document diff --git a/erpnext/education/doctype/student_applicant/student_applicant.py b/erpnext/education/doctype/student_applicant/student_applicant.py index 36a0757531b..5dae9f6ee7d 100644 --- a/erpnext/education/doctype/student_applicant/student_applicant.py +++ b/erpnext/education/doctype/student_applicant/student_applicant.py @@ -1,8 +1,6 @@ -# -*- coding: utf-8 -*-777777yyy # Copyright (c) 2015, Frappe Technologies and contributors # For license information, please see license.txt -from __future__ import print_function, unicode_literals import frappe from frappe import _ diff --git a/erpnext/education/doctype/student_applicant/test_student_applicant.py b/erpnext/education/doctype/student_applicant/test_student_applicant.py index b7258a4ae1d..ba2e9c18863 100644 --- a/erpnext/education/doctype/student_applicant/test_student_applicant.py +++ b/erpnext/education/doctype/student_applicant/test_student_applicant.py @@ -1,7 +1,5 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2015, Frappe Technologies and Contributors # See license.txt -from __future__ import unicode_literals import unittest diff --git a/erpnext/education/doctype/student_attendance/student_attendance.py b/erpnext/education/doctype/student_attendance/student_attendance.py index 3826afb0492..db0fd3719da 100644 --- a/erpnext/education/doctype/student_attendance/student_attendance.py +++ b/erpnext/education/doctype/student_attendance/student_attendance.py @@ -1,8 +1,6 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2015, Frappe Technologies and contributors # For license information, please see license.txt -from __future__ import unicode_literals import frappe from frappe import _ diff --git a/erpnext/education/doctype/student_attendance/student_attendance_dashboard.py b/erpnext/education/doctype/student_attendance/student_attendance_dashboard.py index 489f64d6804..67584529699 100644 --- a/erpnext/education/doctype/student_attendance/student_attendance_dashboard.py +++ b/erpnext/education/doctype/student_attendance/student_attendance_dashboard.py @@ -1,5 +1,3 @@ -from __future__ import unicode_literals - from frappe import _ diff --git a/erpnext/education/doctype/student_attendance/test_student_attendance.py b/erpnext/education/doctype/student_attendance/test_student_attendance.py index d453aeda1c6..6a43e30a33c 100644 --- a/erpnext/education/doctype/student_attendance/test_student_attendance.py +++ b/erpnext/education/doctype/student_attendance/test_student_attendance.py @@ -1,7 +1,5 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2015, Frappe Technologies and Contributors # See license.txt -from __future__ import unicode_literals import unittest diff --git a/erpnext/education/doctype/student_attendance_tool/student_attendance_tool.py b/erpnext/education/doctype/student_attendance_tool/student_attendance_tool.py index 96767deb6d2..4e3f98d6558 100644 --- a/erpnext/education/doctype/student_attendance_tool/student_attendance_tool.py +++ b/erpnext/education/doctype/student_attendance_tool/student_attendance_tool.py @@ -1,8 +1,6 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and contributors # For license information, please see license.txt -from __future__ import unicode_literals import frappe from frappe.model.document import Document diff --git a/erpnext/education/doctype/student_attendance_tool/test_student_attendance_tool.py b/erpnext/education/doctype/student_attendance_tool/test_student_attendance_tool.py index a94a3f235df..c15036fe031 100644 --- a/erpnext/education/doctype/student_attendance_tool/test_student_attendance_tool.py +++ b/erpnext/education/doctype/student_attendance_tool/test_student_attendance_tool.py @@ -1,7 +1,5 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2017, Frappe Technologies Pvt. Ltd. and Contributors # See license.txt -from __future__ import unicode_literals import unittest diff --git a/erpnext/education/doctype/student_batch_name/student_batch_name.py b/erpnext/education/doctype/student_batch_name/student_batch_name.py index ce507160e05..ae59291dcf7 100644 --- a/erpnext/education/doctype/student_batch_name/student_batch_name.py +++ b/erpnext/education/doctype/student_batch_name/student_batch_name.py @@ -1,8 +1,6 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and contributors # For license information, please see license.txt -from __future__ import unicode_literals from frappe.model.document import Document diff --git a/erpnext/education/doctype/student_batch_name/test_student_batch_name.py b/erpnext/education/doctype/student_batch_name/test_student_batch_name.py index 75ebeb29b80..ad9b545e744 100644 --- a/erpnext/education/doctype/student_batch_name/test_student_batch_name.py +++ b/erpnext/education/doctype/student_batch_name/test_student_batch_name.py @@ -1,7 +1,5 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors # See license.txt -from __future__ import unicode_literals import unittest diff --git a/erpnext/education/doctype/student_category/student_category.py b/erpnext/education/doctype/student_category/student_category.py index bb362d5834a..0d7185967ed 100644 --- a/erpnext/education/doctype/student_category/student_category.py +++ b/erpnext/education/doctype/student_category/student_category.py @@ -1,8 +1,6 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and contributors # For license information, please see license.txt -from __future__ import unicode_literals from frappe.model.document import Document diff --git a/erpnext/education/doctype/student_category/student_category_dashboard.py b/erpnext/education/doctype/student_category/student_category_dashboard.py index 92386237883..ebb639e46ef 100644 --- a/erpnext/education/doctype/student_category/student_category_dashboard.py +++ b/erpnext/education/doctype/student_category/student_category_dashboard.py @@ -1,5 +1,3 @@ -from __future__ import unicode_literals - from frappe import _ diff --git a/erpnext/education/doctype/student_category/test_student_category.py b/erpnext/education/doctype/student_category/test_student_category.py index 0893769045e..76469fff250 100644 --- a/erpnext/education/doctype/student_category/test_student_category.py +++ b/erpnext/education/doctype/student_category/test_student_category.py @@ -1,7 +1,5 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors # See license.txt -from __future__ import unicode_literals import unittest diff --git a/erpnext/education/doctype/student_group/student_group.py b/erpnext/education/doctype/student_group/student_group.py index 2347d317317..ceae036e3ed 100644 --- a/erpnext/education/doctype/student_group/student_group.py +++ b/erpnext/education/doctype/student_group/student_group.py @@ -1,8 +1,6 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2015, Frappe Technologies and contributors # For license information, please see license.txt -from __future__ import unicode_literals import frappe from frappe import _ diff --git a/erpnext/education/doctype/student_group/student_group_dashboard.py b/erpnext/education/doctype/student_group/student_group_dashboard.py index 36329bd8d85..d5b930237f4 100644 --- a/erpnext/education/doctype/student_group/student_group_dashboard.py +++ b/erpnext/education/doctype/student_group/student_group_dashboard.py @@ -1,6 +1,5 @@ # Copyright (c) 2020, Frappe Technologies Pvt. Ltd. and Contributors # License: GNU General Public License v3. See license.txt -from __future__ import unicode_literals from frappe import _ diff --git a/erpnext/education/doctype/student_group/test_student_group.py b/erpnext/education/doctype/student_group/test_student_group.py index 06022511e5b..807c63280f2 100644 --- a/erpnext/education/doctype/student_group/test_student_group.py +++ b/erpnext/education/doctype/student_group/test_student_group.py @@ -1,7 +1,5 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2015, Frappe Technologies and Contributors # See license.txt -from __future__ import unicode_literals import unittest diff --git a/erpnext/education/doctype/student_group_creation_tool/student_group_creation_tool.py b/erpnext/education/doctype/student_group_creation_tool/student_group_creation_tool.py index 2007f8aa7cc..8fbfcec3b57 100644 --- a/erpnext/education/doctype/student_group_creation_tool/student_group_creation_tool.py +++ b/erpnext/education/doctype/student_group_creation_tool/student_group_creation_tool.py @@ -1,8 +1,6 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2015, Frappe and contributors # For license information, please see license.txt -from __future__ import unicode_literals import frappe from frappe import _ diff --git a/erpnext/education/doctype/student_group_creation_tool/test_student_group_creation_tool.py b/erpnext/education/doctype/student_group_creation_tool/test_student_group_creation_tool.py index 432da090134..8722f973a84 100644 --- a/erpnext/education/doctype/student_group_creation_tool/test_student_group_creation_tool.py +++ b/erpnext/education/doctype/student_group_creation_tool/test_student_group_creation_tool.py @@ -1,7 +1,5 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2017, Frappe Technologies Pvt. Ltd. and Contributors # See license.txt -from __future__ import unicode_literals import unittest diff --git a/erpnext/education/doctype/student_group_creation_tool_course/student_group_creation_tool_course.py b/erpnext/education/doctype/student_group_creation_tool_course/student_group_creation_tool_course.py index b9d1e0d7fe7..78e45411fd2 100644 --- a/erpnext/education/doctype/student_group_creation_tool_course/student_group_creation_tool_course.py +++ b/erpnext/education/doctype/student_group_creation_tool_course/student_group_creation_tool_course.py @@ -1,8 +1,6 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and contributors # For license information, please see license.txt -from __future__ import unicode_literals from frappe.model.document import Document diff --git a/erpnext/education/doctype/student_group_instructor/student_group_instructor.py b/erpnext/education/doctype/student_group_instructor/student_group_instructor.py index 81a7ed25af5..05ef6fc1164 100644 --- a/erpnext/education/doctype/student_group_instructor/student_group_instructor.py +++ b/erpnext/education/doctype/student_group_instructor/student_group_instructor.py @@ -1,8 +1,6 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2017, Frappe Technologies Pvt. Ltd. and contributors # For license information, please see license.txt -from __future__ import unicode_literals from frappe.model.document import Document diff --git a/erpnext/education/doctype/student_group_student/student_group_student.py b/erpnext/education/doctype/student_group_student/student_group_student.py index 7ee4caec5e3..f9d00abde0b 100644 --- a/erpnext/education/doctype/student_group_student/student_group_student.py +++ b/erpnext/education/doctype/student_group_student/student_group_student.py @@ -1,8 +1,6 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2015, Frappe Technologies and contributors # For license information, please see license.txt -from __future__ import unicode_literals from frappe.model.document import Document diff --git a/erpnext/education/doctype/student_guardian/student_guardian.py b/erpnext/education/doctype/student_guardian/student_guardian.py index 56d7df7d0a8..0843acfd50a 100644 --- a/erpnext/education/doctype/student_guardian/student_guardian.py +++ b/erpnext/education/doctype/student_guardian/student_guardian.py @@ -1,8 +1,6 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and contributors # For license information, please see license.txt -from __future__ import unicode_literals from frappe.model.document import Document diff --git a/erpnext/education/doctype/student_language/student_language.py b/erpnext/education/doctype/student_language/student_language.py index 6ec0b1fc6e1..d578c9a0b66 100644 --- a/erpnext/education/doctype/student_language/student_language.py +++ b/erpnext/education/doctype/student_language/student_language.py @@ -1,8 +1,6 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and contributors # For license information, please see license.txt -from __future__ import unicode_literals from frappe.model.document import Document diff --git a/erpnext/education/doctype/student_language/test_student_language.py b/erpnext/education/doctype/student_language/test_student_language.py index 1d7c003ae5e..718896c6c51 100644 --- a/erpnext/education/doctype/student_language/test_student_language.py +++ b/erpnext/education/doctype/student_language/test_student_language.py @@ -1,7 +1,5 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors # See license.txt -from __future__ import unicode_literals import unittest diff --git a/erpnext/education/doctype/student_leave_application/student_leave_application.py b/erpnext/education/doctype/student_leave_application/student_leave_application.py index 50c14aae22b..b1eda9a3c10 100644 --- a/erpnext/education/doctype/student_leave_application/student_leave_application.py +++ b/erpnext/education/doctype/student_leave_application/student_leave_application.py @@ -1,8 +1,6 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and contributors # For license information, please see license.txt -from __future__ import unicode_literals from datetime import timedelta diff --git a/erpnext/education/doctype/student_leave_application/student_leave_application_dashboard.py b/erpnext/education/doctype/student_leave_application/student_leave_application_dashboard.py index 2674f5415d9..d01790d645a 100644 --- a/erpnext/education/doctype/student_leave_application/student_leave_application_dashboard.py +++ b/erpnext/education/doctype/student_leave_application/student_leave_application_dashboard.py @@ -1,6 +1,3 @@ -from __future__ import unicode_literals - - def get_data(): return { 'fieldname': 'leave_application', diff --git a/erpnext/education/doctype/student_leave_application/test_student_leave_application.py b/erpnext/education/doctype/student_leave_application/test_student_leave_application.py index 506dc738d88..92e82c5b8a1 100644 --- a/erpnext/education/doctype/student_leave_application/test_student_leave_application.py +++ b/erpnext/education/doctype/student_leave_application/test_student_leave_application.py @@ -1,7 +1,5 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors # See license.txt -from __future__ import unicode_literals import unittest diff --git a/erpnext/education/doctype/student_log/student_log.py b/erpnext/education/doctype/student_log/student_log.py index 2ca49ca12d3..b95f34e0493 100644 --- a/erpnext/education/doctype/student_log/student_log.py +++ b/erpnext/education/doctype/student_log/student_log.py @@ -1,8 +1,6 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and contributors # For license information, please see license.txt -from __future__ import unicode_literals from frappe.model.document import Document diff --git a/erpnext/education/doctype/student_log/test_student_log.py b/erpnext/education/doctype/student_log/test_student_log.py index 533191f3b47..91fdb3c8167 100644 --- a/erpnext/education/doctype/student_log/test_student_log.py +++ b/erpnext/education/doctype/student_log/test_student_log.py @@ -1,7 +1,5 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors # See license.txt -from __future__ import unicode_literals import unittest diff --git a/erpnext/education/doctype/student_report_generation_tool/student_report_generation_tool.py b/erpnext/education/doctype/student_report_generation_tool/student_report_generation_tool.py index 1cf79213150..43802abea65 100644 --- a/erpnext/education/doctype/student_report_generation_tool/student_report_generation_tool.py +++ b/erpnext/education/doctype/student_report_generation_tool/student_report_generation_tool.py @@ -1,8 +1,6 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2018, Frappe Technologies Pvt. Ltd. and contributors # For license information, please see license.txt -from __future__ import unicode_literals import json diff --git a/erpnext/education/doctype/student_report_generation_tool/test_student_report_generation_tool.py b/erpnext/education/doctype/student_report_generation_tool/test_student_report_generation_tool.py index f6227136d9d..e37881f0125 100644 --- a/erpnext/education/doctype/student_report_generation_tool/test_student_report_generation_tool.py +++ b/erpnext/education/doctype/student_report_generation_tool/test_student_report_generation_tool.py @@ -1,7 +1,5 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2018, Frappe Technologies Pvt. Ltd. and Contributors # See license.txt -from __future__ import unicode_literals import unittest diff --git a/erpnext/education/doctype/student_sibling/student_sibling.py b/erpnext/education/doctype/student_sibling/student_sibling.py index b36cf59dbb3..9ee0667d14e 100644 --- a/erpnext/education/doctype/student_sibling/student_sibling.py +++ b/erpnext/education/doctype/student_sibling/student_sibling.py @@ -1,8 +1,6 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and contributors # For license information, please see license.txt -from __future__ import unicode_literals from frappe.model.document import Document diff --git a/erpnext/education/doctype/student_siblings/student_siblings.py b/erpnext/education/doctype/student_siblings/student_siblings.py index 412cf050c16..ee89f4f1575 100644 --- a/erpnext/education/doctype/student_siblings/student_siblings.py +++ b/erpnext/education/doctype/student_siblings/student_siblings.py @@ -1,8 +1,6 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and contributors # For license information, please see license.txt -from __future__ import unicode_literals from frappe.model.document import Document diff --git a/erpnext/education/doctype/topic/test_topic.py b/erpnext/education/doctype/topic/test_topic.py index b6c6c7516fa..d1d664bb21a 100644 --- a/erpnext/education/doctype/topic/test_topic.py +++ b/erpnext/education/doctype/topic/test_topic.py @@ -1,7 +1,5 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2018, Frappe Technologies Pvt. Ltd. and Contributors # See license.txt -from __future__ import unicode_literals import unittest diff --git a/erpnext/education/doctype/topic/topic.py b/erpnext/education/doctype/topic/topic.py index 1834b2e060c..146f57453ad 100644 --- a/erpnext/education/doctype/topic/topic.py +++ b/erpnext/education/doctype/topic/topic.py @@ -1,8 +1,6 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2018, Frappe Technologies Pvt. Ltd. and contributors # For license information, please see license.txt -from __future__ import unicode_literals import json diff --git a/erpnext/education/doctype/topic_content/test_topic_content.py b/erpnext/education/doctype/topic_content/test_topic_content.py index 6fdcbdae717..56bb40968ca 100644 --- a/erpnext/education/doctype/topic_content/test_topic_content.py +++ b/erpnext/education/doctype/topic_content/test_topic_content.py @@ -1,7 +1,5 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2018, Frappe Technologies Pvt. Ltd. and Contributors # See license.txt -from __future__ import unicode_literals import unittest diff --git a/erpnext/education/doctype/topic_content/topic_content.py b/erpnext/education/doctype/topic_content/topic_content.py index 9339bbde5aa..88d0eee73ab 100644 --- a/erpnext/education/doctype/topic_content/topic_content.py +++ b/erpnext/education/doctype/topic_content/topic_content.py @@ -1,8 +1,6 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2018, Frappe Technologies Pvt. Ltd. and contributors # For license information, please see license.txt -from __future__ import unicode_literals from frappe.model.document import Document diff --git a/erpnext/education/report/absent_student_report/absent_student_report.py b/erpnext/education/report/absent_student_report/absent_student_report.py index d5b66757fcd..c274d333492 100644 --- a/erpnext/education/report/absent_student_report/absent_student_report.py +++ b/erpnext/education/report/absent_student_report/absent_student_report.py @@ -1,7 +1,6 @@ # Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors # License: GNU General Public License v3. See license.txt -from __future__ import unicode_literals import frappe from frappe import _, msgprint diff --git a/erpnext/education/report/assessment_plan_status/assessment_plan_status.py b/erpnext/education/report/assessment_plan_status/assessment_plan_status.py index 64ceb42731a..86f2451cbf0 100644 --- a/erpnext/education/report/assessment_plan_status/assessment_plan_status.py +++ b/erpnext/education/report/assessment_plan_status/assessment_plan_status.py @@ -1,7 +1,6 @@ # Copyright (c) 2013, Frappe Technologies Pvt. Ltd. and contributors # For license information, please see license.txt -from __future__ import unicode_literals from itertools import groupby diff --git a/erpnext/education/report/course_wise_assessment_report/course_wise_assessment_report.py b/erpnext/education/report/course_wise_assessment_report/course_wise_assessment_report.py index ad07ee1949c..38eef68d0e7 100644 --- a/erpnext/education/report/course_wise_assessment_report/course_wise_assessment_report.py +++ b/erpnext/education/report/course_wise_assessment_report/course_wise_assessment_report.py @@ -1,7 +1,6 @@ # Copyright (c) 2013, Frappe Technologies Pvt. Ltd. and contributors # For license information, please see license.txt -from __future__ import unicode_literals from collections import OrderedDict, defaultdict diff --git a/erpnext/education/report/final_assessment_grades/final_assessment_grades.py b/erpnext/education/report/final_assessment_grades/final_assessment_grades.py index ae7f34b5e1c..b0428678045 100644 --- a/erpnext/education/report/final_assessment_grades/final_assessment_grades.py +++ b/erpnext/education/report/final_assessment_grades/final_assessment_grades.py @@ -1,7 +1,6 @@ # Copyright (c) 2013, Frappe Technologies Pvt. Ltd. and contributors # For license information, please see license.txt -from __future__ import unicode_literals from collections import defaultdict diff --git a/erpnext/education/report/program_wise_fee_collection/program_wise_fee_collection.py b/erpnext/education/report/program_wise_fee_collection/program_wise_fee_collection.py index 1717ed55aec..0599dadf934 100644 --- a/erpnext/education/report/program_wise_fee_collection/program_wise_fee_collection.py +++ b/erpnext/education/report/program_wise_fee_collection/program_wise_fee_collection.py @@ -1,7 +1,6 @@ # Copyright (c) 2013, Frappe Technologies Pvt. Ltd. and contributors # For license information, please see license.txt -from __future__ import unicode_literals import frappe from frappe import _ diff --git a/erpnext/education/report/student_and_guardian_contact_details/student_and_guardian_contact_details.py b/erpnext/education/report/student_and_guardian_contact_details/student_and_guardian_contact_details.py index a21a93686ef..7097b8072b2 100644 --- a/erpnext/education/report/student_and_guardian_contact_details/student_and_guardian_contact_details.py +++ b/erpnext/education/report/student_and_guardian_contact_details/student_and_guardian_contact_details.py @@ -1,7 +1,6 @@ # Copyright (c) 2013, Frappe Technologies Pvt. Ltd. and contributors # For license information, please see license.txt -from __future__ import unicode_literals import frappe from frappe import _ diff --git a/erpnext/education/report/student_batch_wise_attendance/student_batch_wise_attendance.py b/erpnext/education/report/student_batch_wise_attendance/student_batch_wise_attendance.py index b65350f1b22..52055dceb8c 100644 --- a/erpnext/education/report/student_batch_wise_attendance/student_batch_wise_attendance.py +++ b/erpnext/education/report/student_batch_wise_attendance/student_batch_wise_attendance.py @@ -1,7 +1,6 @@ # Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors # License: GNU General Public License v3. See license.txt -from __future__ import unicode_literals import frappe from frappe import _, msgprint diff --git a/erpnext/education/report/student_fee_collection/student_fee_collection.json b/erpnext/education/report/student_fee_collection/student_fee_collection.json index 8deb865ebcd..c0229a2ee26 100644 --- a/erpnext/education/report/student_fee_collection/student_fee_collection.json +++ b/erpnext/education/report/student_fee_collection/student_fee_collection.json @@ -1,5 +1,5 @@ { - "add_total_row": 0, + "add_total_row": 1, "creation": "2016-06-22 02:58:41.024538", "disable_prepared_report": 0, "disabled": 0, @@ -13,7 +13,7 @@ "name": "Student Fee Collection", "owner": "Administrator", "prepared_report": 0, - "query": "SELECT\n student as \"Student:Link/Student:200\",\n student_name as \"Student Name::200\",\n sum(grand_total) - sum(outstanding_amount) as \"Paid Amount:Currency:150\",\n sum(outstanding_amount) as \"Outstanding Amount:Currency:150\",\n sum(grand_total) as \"Grand Total:Currency:150\"\nFROM\n `tabFees` \nGROUP BY\n student", + "query": "SELECT\n student as \"Student:Link/Student:200\",\n student_name as \"Student Name::200\",\n sum(grand_total) - sum(outstanding_amount) as \"Paid Amount:Currency:150\",\n sum(outstanding_amount) as \"Outstanding Amount:Currency:150\",\n sum(grand_total) as \"Grand Total:Currency:150\"\nFROM\n `tabFees` \nWHERE\n docstatus=1 \nGROUP BY\n student", "ref_doctype": "Fees", "report_name": "Student Fee Collection", "report_type": "Query Report", @@ -22,4 +22,4 @@ "role": "Academics User" } ] -} \ No newline at end of file +} diff --git a/erpnext/education/report/student_monthly_attendance_sheet/student_monthly_attendance_sheet.py b/erpnext/education/report/student_monthly_attendance_sheet/student_monthly_attendance_sheet.py index f6d9c5a012e..1166a75b2cc 100644 --- a/erpnext/education/report/student_monthly_attendance_sheet/student_monthly_attendance_sheet.py +++ b/erpnext/education/report/student_monthly_attendance_sheet/student_monthly_attendance_sheet.py @@ -1,7 +1,6 @@ # Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors # License: GNU General Public License v3. See license.txt -from __future__ import unicode_literals import frappe from frappe import _ diff --git a/erpnext/education/setup.py b/erpnext/education/setup.py index 5c4092849a7..b7169261764 100644 --- a/erpnext/education/setup.py +++ b/erpnext/education/setup.py @@ -1,8 +1,6 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2017, Frappe Technologies Pvt. Ltd. and contributors # For license information, please see license.txt -from __future__ import unicode_literals import frappe from erpnext.setup.utils import insert_record diff --git a/erpnext/education/utils.py b/erpnext/education/utils.py index 33394e17963..a7a15d18ce8 100644 --- a/erpnext/education/utils.py +++ b/erpnext/education/utils.py @@ -1,8 +1,5 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2015, Frappe Technologies and contributors -from __future__ import division, unicode_literals - import frappe from frappe import _ diff --git a/erpnext/education/web_form/student_applicant/student_applicant.py b/erpnext/education/web_form/student_applicant/student_applicant.py index f57de916dd1..02e3e933330 100644 --- a/erpnext/education/web_form/student_applicant/student_applicant.py +++ b/erpnext/education/web_form/student_applicant/student_applicant.py @@ -1,6 +1,3 @@ -from __future__ import unicode_literals - - def get_context(context): # do your magic here pass diff --git a/erpnext/education/workspace/education/education.json b/erpnext/education/workspace/education/education.json index c58ddd63cfe..14652956583 100644 --- a/erpnext/education/workspace/education/education.json +++ b/erpnext/education/workspace/education/education.json @@ -1,5 +1,4 @@ { - "category": "", "charts": [ { "chart_name": "Program Enrollments", @@ -8,18 +7,12 @@ ], "content": "[{\"type\": \"onboarding\", \"data\": {\"onboarding_name\":\"Education\", \"col\": 12}}, {\"type\": \"chart\", \"data\": {\"chart_name\": \"Program Enrollments\", \"col\": 12}}, {\"type\": \"spacer\", \"data\": {\"col\": 12}}, {\"type\": \"header\", \"data\": {\"text\": \"Your Shortcuts\", \"level\": 4, \"col\": 12}}, {\"type\": \"shortcut\", \"data\": {\"shortcut_name\": \"Student\", \"col\": 4}}, {\"type\": \"shortcut\", \"data\": {\"shortcut_name\": \"Instructor\", \"col\": 4}}, {\"type\": \"shortcut\", \"data\": {\"shortcut_name\": \"Program\", \"col\": 4}}, {\"type\": \"shortcut\", \"data\": {\"shortcut_name\": \"Course\", \"col\": 4}}, {\"type\": \"shortcut\", \"data\": {\"shortcut_name\": \"Fees\", \"col\": 4}}, {\"type\": \"shortcut\", \"data\": {\"shortcut_name\": \"Student Monthly Attendance Sheet\", \"col\": 4}}, {\"type\": \"shortcut\", \"data\": {\"shortcut_name\": \"Course Scheduling Tool\", \"col\": 4}}, {\"type\": \"shortcut\", \"data\": {\"shortcut_name\": \"Student Attendance Tool\", \"col\": 4}}, {\"type\": \"shortcut\", \"data\": {\"shortcut_name\": \"Dashboard\", \"col\": 4}}, {\"type\": \"spacer\", \"data\": {\"col\": 12}}, {\"type\": \"header\", \"data\": {\"text\": \"Reports & Masters\", \"level\": 4, \"col\": 12}}, {\"type\": \"card\", \"data\": {\"card_name\": \"Student and Instructor\", \"col\": 4}}, {\"type\": \"card\", \"data\": {\"card_name\": \"Masters\", \"col\": 4}}, {\"type\": \"card\", \"data\": {\"card_name\": \"Content Masters\", \"col\": 4}}, {\"type\": \"card\", \"data\": {\"card_name\": \"Settings\", \"col\": 4}}, {\"type\": \"card\", \"data\": {\"card_name\": \"Admission\", \"col\": 4}}, {\"type\": \"card\", \"data\": {\"card_name\": \"Fees\", \"col\": 4}}, {\"type\": \"card\", \"data\": {\"card_name\": \"Schedule\", \"col\": 4}}, {\"type\": \"card\", \"data\": {\"card_name\": \"Attendance\", \"col\": 4}}, {\"type\": \"card\", \"data\": {\"card_name\": \"LMS Activity\", \"col\": 4}}, {\"type\": \"card\", \"data\": {\"card_name\": \"Assessment\", \"col\": 4}}, {\"type\": \"card\", \"data\": {\"card_name\": \"Assessment Reports\", \"col\": 4}}, {\"type\": \"card\", \"data\": {\"card_name\": \"Tools\", \"col\": 4}}, {\"type\": \"card\", \"data\": {\"card_name\": \"Other Reports\", \"col\": 4}}]", "creation": "2020-03-02 17:22:57.066401", - "developer_mode_only": 0, - "disable_user_customization": 0, "docstatus": 0, "doctype": "Workspace", - "extends": "", - "extends_another_page": 0, "for_user": "", "hide_custom": 0, "icon": "education", "idx": 0, - "is_default": 0, - "is_standard": 0, "label": "Education", "links": [ { @@ -699,15 +692,12 @@ "type": "Link" } ], - "modified": "2021-08-05 12:15:57.929275", + "modified": "2021-08-05 12:15:57.929276", "modified_by": "Administrator", "module": "Education", "name": "Education", - "onboarding": "Education", "owner": "Administrator", "parent_page": "", - "pin_to_bottom": 0, - "pin_to_top": 0, "public": 1, "restrict_to_domain": "Education", "roles": [], diff --git a/erpnext/erpnext_integrations/connectors/github_connection.py b/erpnext/erpnext_integrations/connectors/github_connection.py index ab7708df305..f28065e7248 100644 --- a/erpnext/erpnext_integrations/connectors/github_connection.py +++ b/erpnext/erpnext_integrations/connectors/github_connection.py @@ -1,4 +1,3 @@ -from __future__ import unicode_literals import frappe from frappe.data_migration.doctype.data_migration_connector.connectors.base import BaseConnection from github import Github diff --git a/erpnext/erpnext_integrations/connectors/woocommerce_connection.py b/erpnext/erpnext_integrations/connectors/woocommerce_connection.py index 192ec147e36..9409485a9f6 100644 --- a/erpnext/erpnext_integrations/connectors/woocommerce_connection.py +++ b/erpnext/erpnext_integrations/connectors/woocommerce_connection.py @@ -1,6 +1,3 @@ - -from __future__ import unicode_literals - import base64 import hashlib import hmac @@ -22,8 +19,7 @@ def verify_request(): ) if frappe.request.data and \ - frappe.get_request_header("X-Wc-Webhook-Signature") and \ - not sig == bytes(frappe.get_request_header("X-Wc-Webhook-Signature").encode()): + not sig == frappe.get_request_header("X-Wc-Webhook-Signature", "").encode(): frappe.throw(_("Unverified Webhook Data")) frappe.set_user(woocommerce_settings.creation_user) diff --git a/erpnext/erpnext_integrations/data_migration_mapping/issue_to_task/__init__.py b/erpnext/erpnext_integrations/data_migration_mapping/issue_to_task/__init__.py index 5a4a57c2e25..1d0dfa5c696 100644 --- a/erpnext/erpnext_integrations/data_migration_mapping/issue_to_task/__init__.py +++ b/erpnext/erpnext_integrations/data_migration_mapping/issue_to_task/__init__.py @@ -1,5 +1,3 @@ -from __future__ import unicode_literals - import frappe diff --git a/erpnext/erpnext_integrations/data_migration_mapping/milestone_to_project/__init__.py b/erpnext/erpnext_integrations/data_migration_mapping/milestone_to_project/__init__.py index bab8031e024..212f81b5f9f 100644 --- a/erpnext/erpnext_integrations/data_migration_mapping/milestone_to_project/__init__.py +++ b/erpnext/erpnext_integrations/data_migration_mapping/milestone_to_project/__init__.py @@ -1,6 +1,3 @@ -from __future__ import unicode_literals - - def pre_process(milestone): return { 'title': milestone.title, diff --git a/erpnext/erpnext_integrations/doctype/amazon_mws_settings/amazon_methods.py b/erpnext/erpnext_integrations/doctype/amazon_mws_settings/amazon_methods.py index a757a43b59c..66826ba8d75 100644 --- a/erpnext/erpnext_integrations/doctype/amazon_mws_settings/amazon_methods.py +++ b/erpnext/erpnext_integrations/doctype/amazon_mws_settings/amazon_methods.py @@ -1,8 +1,6 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2018, Frappe Technologies and contributors # For license information, please see license.txt -from __future__ import unicode_literals import csv import math @@ -32,7 +30,7 @@ def get_products_details(): #Get ASIN Codes string_io = StringIO(frappe.safe_decode(listings_response.original)) - csv_rows = list(csv.reader(string_io, delimiter=str('\t'))) + csv_rows = list(csv.reader(string_io, delimiter='\t')) asin_list = list(set([row[1] for row in csv_rows[1:]])) #break into chunks of 10 asin_chunked_list = list(chunks(asin_list, 10)) diff --git a/erpnext/erpnext_integrations/doctype/amazon_mws_settings/amazon_mws_api.py b/erpnext/erpnext_integrations/doctype/amazon_mws_settings/amazon_mws_api.py index 652fa9200d9..4caf137455a 100755 --- a/erpnext/erpnext_integrations/doctype/amazon_mws_settings/amazon_mws_api.py +++ b/erpnext/erpnext_integrations/doctype/amazon_mws_settings/amazon_mws_api.py @@ -1,10 +1,8 @@ #!/usr/bin/env python -# -*- coding: utf-8 -*- # # Basic interface to Amazon MWS # Based on http://code.google.com/p/amazon-mws-python # Extended to include finances object -from __future__ import unicode_literals import base64 import hashlib diff --git a/erpnext/erpnext_integrations/doctype/amazon_mws_settings/amazon_mws_settings.py b/erpnext/erpnext_integrations/doctype/amazon_mws_settings/amazon_mws_settings.py index ac59eb7925c..c1f460f49b6 100644 --- a/erpnext/erpnext_integrations/doctype/amazon_mws_settings/amazon_mws_settings.py +++ b/erpnext/erpnext_integrations/doctype/amazon_mws_settings/amazon_mws_settings.py @@ -1,8 +1,6 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2018, Frappe Technologies and contributors # For license information, please see license.txt -from __future__ import unicode_literals import dateutil import frappe diff --git a/erpnext/erpnext_integrations/doctype/amazon_mws_settings/test_amazon_mws_settings.py b/erpnext/erpnext_integrations/doctype/amazon_mws_settings/test_amazon_mws_settings.py index 844df59576a..4be7960deda 100644 --- a/erpnext/erpnext_integrations/doctype/amazon_mws_settings/test_amazon_mws_settings.py +++ b/erpnext/erpnext_integrations/doctype/amazon_mws_settings/test_amazon_mws_settings.py @@ -1,7 +1,5 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2018, Frappe Technologies Pvt. Ltd. and Contributors # See license.txt -from __future__ import unicode_literals import unittest diff --git a/erpnext/erpnext_integrations/doctype/amazon_mws_settings/xml_utils.py b/erpnext/erpnext_integrations/doctype/amazon_mws_settings/xml_utils.py index 88ef64d307c..d9dfc6f72d4 100644 --- a/erpnext/erpnext_integrations/doctype/amazon_mws_settings/xml_utils.py +++ b/erpnext/erpnext_integrations/doctype/amazon_mws_settings/xml_utils.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- """ Created on Tue Jun 26 15:42:07 2012 @@ -6,7 +5,6 @@ Borrowed from https://github.com/timotheus/ebaysdk-python @author: pierre """ -from __future__ import unicode_literals import re import xml.etree.ElementTree as ET diff --git a/erpnext/erpnext_integrations/doctype/exotel_settings/exotel_settings.py b/erpnext/erpnext_integrations/doctype/exotel_settings/exotel_settings.py index f1314fc122f..e84093cae09 100644 --- a/erpnext/erpnext_integrations/doctype/exotel_settings/exotel_settings.py +++ b/erpnext/erpnext_integrations/doctype/exotel_settings/exotel_settings.py @@ -1,8 +1,6 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2019, Frappe Technologies Pvt. Ltd. and contributors # For license information, please see license.txt -from __future__ import unicode_literals import frappe import requests diff --git a/erpnext/erpnext_integrations/doctype/gocardless_mandate/gocardless_mandate.py b/erpnext/erpnext_integrations/doctype/gocardless_mandate/gocardless_mandate.py index b416ce8808f..bceb3caebdf 100644 --- a/erpnext/erpnext_integrations/doctype/gocardless_mandate/gocardless_mandate.py +++ b/erpnext/erpnext_integrations/doctype/gocardless_mandate/gocardless_mandate.py @@ -1,8 +1,6 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2018, Frappe Technologies and contributors # For license information, please see license.txt -from __future__ import unicode_literals from frappe.model.document import Document diff --git a/erpnext/erpnext_integrations/doctype/gocardless_mandate/test_gocardless_mandate.py b/erpnext/erpnext_integrations/doctype/gocardless_mandate/test_gocardless_mandate.py index 1b76ee5afc7..0c1952a16a9 100644 --- a/erpnext/erpnext_integrations/doctype/gocardless_mandate/test_gocardless_mandate.py +++ b/erpnext/erpnext_integrations/doctype/gocardless_mandate/test_gocardless_mandate.py @@ -1,7 +1,5 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2018, Frappe Technologies and Contributors # See license.txt -from __future__ import unicode_literals import unittest diff --git a/erpnext/erpnext_integrations/doctype/gocardless_settings/__init__.py b/erpnext/erpnext_integrations/doctype/gocardless_settings/__init__.py index d003edb9b0e..bb62c395a5b 100644 --- a/erpnext/erpnext_integrations/doctype/gocardless_settings/__init__.py +++ b/erpnext/erpnext_integrations/doctype/gocardless_settings/__init__.py @@ -1,8 +1,6 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2018, Frappe Technologies and contributors # For license information, please see license.txt -from __future__ import unicode_literals import hashlib import hmac diff --git a/erpnext/erpnext_integrations/doctype/gocardless_settings/gocardless_settings.py b/erpnext/erpnext_integrations/doctype/gocardless_settings/gocardless_settings.py index 6484973106a..e242ace60f7 100644 --- a/erpnext/erpnext_integrations/doctype/gocardless_settings/gocardless_settings.py +++ b/erpnext/erpnext_integrations/doctype/gocardless_settings/gocardless_settings.py @@ -1,8 +1,6 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2018, Frappe Technologies and contributors # For license information, please see license.txt -from __future__ import unicode_literals import frappe import gocardless_pro diff --git a/erpnext/erpnext_integrations/doctype/gocardless_settings/test_gocardless_settings.py b/erpnext/erpnext_integrations/doctype/gocardless_settings/test_gocardless_settings.py index b17aef50986..379afe51ddc 100644 --- a/erpnext/erpnext_integrations/doctype/gocardless_settings/test_gocardless_settings.py +++ b/erpnext/erpnext_integrations/doctype/gocardless_settings/test_gocardless_settings.py @@ -1,7 +1,5 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2018, Frappe Technologies and Contributors # See license.txt -from __future__ import unicode_literals import unittest diff --git a/erpnext/erpnext_integrations/doctype/mpesa_settings/mpesa_settings.py b/erpnext/erpnext_integrations/doctype/mpesa_settings/mpesa_settings.py index 4ce85e58a61..e7b4a30e0a5 100644 --- a/erpnext/erpnext_integrations/doctype/mpesa_settings/mpesa_settings.py +++ b/erpnext/erpnext_integrations/doctype/mpesa_settings/mpesa_settings.py @@ -1,9 +1,7 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2020, Frappe Technologies and contributors # For license information, please see license.txt -from __future__ import unicode_literals from json import dumps, loads @@ -143,6 +141,9 @@ def verify_transaction(**kwargs): transaction_response = frappe._dict(kwargs["Body"]["stkCallback"]) checkout_id = getattr(transaction_response, "CheckoutRequestID", "") + if not isinstance(checkout_id, str): + frappe.throw(_("Invalid Checkout Request ID")) + integration_request = frappe.get_doc("Integration Request", checkout_id) transaction_data = frappe._dict(loads(integration_request.data)) total_paid = 0 # for multiple integration request made against a pos invoice @@ -233,6 +234,9 @@ def process_balance_info(**kwargs): account_balance_response = frappe._dict(kwargs["Result"]) conversation_id = getattr(account_balance_response, "ConversationID", "") + if not isinstance(conversation_id, str): + frappe.throw(_("Invalid Conversation ID")) + request = frappe.get_doc("Integration Request", conversation_id) if request.status == "Completed": diff --git a/erpnext/erpnext_integrations/doctype/mpesa_settings/test_mpesa_settings.py b/erpnext/erpnext_integrations/doctype/mpesa_settings/test_mpesa_settings.py index de81b821321..3945afab69a 100644 --- a/erpnext/erpnext_integrations/doctype/mpesa_settings/test_mpesa_settings.py +++ b/erpnext/erpnext_integrations/doctype/mpesa_settings/test_mpesa_settings.py @@ -1,7 +1,5 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2020, Frappe Technologies Pvt. Ltd. and Contributors # See license.txt -from __future__ import unicode_literals import unittest from json import dumps diff --git a/erpnext/erpnext_integrations/doctype/plaid_settings/plaid_connector.py b/erpnext/erpnext_integrations/doctype/plaid_settings/plaid_connector.py index d4cf56af6b2..0b552f9bbf4 100644 --- a/erpnext/erpnext_integrations/doctype/plaid_settings/plaid_connector.py +++ b/erpnext/erpnext_integrations/doctype/plaid_settings/plaid_connector.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2018, Frappe Technologies Pvt. Ltd. and contributors # For license information, please see license.txt diff --git a/erpnext/erpnext_integrations/doctype/plaid_settings/plaid_settings.py b/erpnext/erpnext_integrations/doctype/plaid_settings/plaid_settings.py index d2748c2faad..7e6f146ce3f 100644 --- a/erpnext/erpnext_integrations/doctype/plaid_settings/plaid_settings.py +++ b/erpnext/erpnext_integrations/doctype/plaid_settings/plaid_settings.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2018, Frappe Technologies Pvt. Ltd. and contributors # For license information, please see license.txt @@ -85,10 +84,8 @@ def add_bank_accounts(response, bank, company): if not acc_subtype: add_account_subtype(account["subtype"]) - existing_bank_account = frappe.db.exists("Bank Account", { - 'account_name': account["name"], - 'bank': bank["bank_name"] - }) + bank_account_name = "{} - {}".format(account["name"], bank["bank_name"]) + existing_bank_account = frappe.db.exists("Bank Account", bank_account_name) if not existing_bank_account: try: @@ -197,6 +194,7 @@ def get_transactions(bank, bank_account=None, start_date=None, end_date=None): plaid = PlaidConnector(access_token) + transactions = [] try: transactions = plaid.get_transactions(start_date=start_date, end_date=end_date, account_id=account_id) except ItemError as e: @@ -205,7 +203,7 @@ def get_transactions(bank, bank_account=None, start_date=None, end_date=None): msg += _("Please refresh or reset the Plaid linking of the Bank {}.").format(bank) + " " frappe.log_error(msg, title=_("Plaid Link Refresh Required")) - return transactions or [] + return transactions def new_bank_transaction(transaction): diff --git a/erpnext/erpnext_integrations/doctype/plaid_settings/test_plaid_settings.py b/erpnext/erpnext_integrations/doctype/plaid_settings/test_plaid_settings.py index 32b5b8f2657..535d7fa7997 100644 --- a/erpnext/erpnext_integrations/doctype/plaid_settings/test_plaid_settings.py +++ b/erpnext/erpnext_integrations/doctype/plaid_settings/test_plaid_settings.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2018, Frappe Technologies Pvt. Ltd. and Contributors # See license.txt diff --git a/erpnext/erpnext_integrations/doctype/quickbooks_migrator/quickbooks_migrator.py b/erpnext/erpnext_integrations/doctype/quickbooks_migrator/quickbooks_migrator.py index 39b9bb232e0..5de568272a0 100644 --- a/erpnext/erpnext_integrations/doctype/quickbooks_migrator/quickbooks_migrator.py +++ b/erpnext/erpnext_integrations/doctype/quickbooks_migrator/quickbooks_migrator.py @@ -1,8 +1,6 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2018, Frappe Technologies Pvt. Ltd. and contributors # For license information, please see license.txt -from __future__ import unicode_literals import json import traceback diff --git a/erpnext/erpnext_integrations/doctype/quickbooks_migrator/test_quickbooks_migrator.py b/erpnext/erpnext_integrations/doctype/quickbooks_migrator/test_quickbooks_migrator.py index 5604b40d140..92e79ec8a4a 100644 --- a/erpnext/erpnext_integrations/doctype/quickbooks_migrator/test_quickbooks_migrator.py +++ b/erpnext/erpnext_integrations/doctype/quickbooks_migrator/test_quickbooks_migrator.py @@ -1,7 +1,5 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2018, Frappe Technologies Pvt. Ltd. and Contributors # See license.txt -from __future__ import unicode_literals import unittest diff --git a/erpnext/erpnext_integrations/doctype/tally_migration/tally_migration.py b/erpnext/erpnext_integrations/doctype/tally_migration/tally_migration.py index e1e7f62df4e..54ed6f7d115 100644 --- a/erpnext/erpnext_integrations/doctype/tally_migration/tally_migration.py +++ b/erpnext/erpnext_integrations/doctype/tally_migration/tally_migration.py @@ -1,8 +1,6 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2019, Frappe Technologies Pvt. Ltd. and contributors # For license information, please see license.txt -from __future__ import unicode_literals import json import re diff --git a/erpnext/erpnext_integrations/doctype/tally_migration/test_tally_migration.py b/erpnext/erpnext_integrations/doctype/tally_migration/test_tally_migration.py index aae8f6d4db0..7a61abaee63 100644 --- a/erpnext/erpnext_integrations/doctype/tally_migration/test_tally_migration.py +++ b/erpnext/erpnext_integrations/doctype/tally_migration/test_tally_migration.py @@ -1,7 +1,5 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2019, Frappe Technologies Pvt. Ltd. and Contributors # See license.txt -from __future__ import unicode_literals import unittest diff --git a/erpnext/healthcare/doctype/clinical_procedure/__init__.py b/erpnext/erpnext_integrations/doctype/taxjar_nexus/__init__.py similarity index 100% rename from erpnext/healthcare/doctype/clinical_procedure/__init__.py rename to erpnext/erpnext_integrations/doctype/taxjar_nexus/__init__.py diff --git a/erpnext/erpnext_integrations/doctype/taxjar_nexus/taxjar_nexus.json b/erpnext/erpnext_integrations/doctype/taxjar_nexus/taxjar_nexus.json new file mode 100644 index 00000000000..d4d4a512b58 --- /dev/null +++ b/erpnext/erpnext_integrations/doctype/taxjar_nexus/taxjar_nexus.json @@ -0,0 +1,51 @@ +{ + "actions": [], + "allow_rename": 1, + "creation": "2021-09-11 05:09:53.773838", + "doctype": "DocType", + "engine": "InnoDB", + "field_order": [ + "region", + "region_code", + "country", + "country_code" + ], + "fields": [ + { + "fieldname": "region", + "fieldtype": "Data", + "in_list_view": 1, + "label": "Region" + }, + { + "fieldname": "region_code", + "fieldtype": "Data", + "in_list_view": 1, + "label": "Region Code" + }, + { + "fieldname": "country", + "fieldtype": "Data", + "in_list_view": 1, + "label": "Country" + }, + { + "fieldname": "country_code", + "fieldtype": "Data", + "in_list_view": 1, + "label": "Country Code" + } + ], + "index_web_pages_for_search": 1, + "istable": 1, + "links": [], + "modified": "2021-09-14 05:33:06.444710", + "modified_by": "Administrator", + "module": "ERPNext Integrations", + "name": "TaxJar Nexus", + "owner": "Administrator", + "permissions": [], + "sort_field": "modified", + "sort_order": "DESC", + "track_changes": 1 +} \ No newline at end of file diff --git a/erpnext/erpnext_integrations/doctype/taxjar_nexus/taxjar_nexus.py b/erpnext/erpnext_integrations/doctype/taxjar_nexus/taxjar_nexus.py new file mode 100644 index 00000000000..c24aa8ca7d4 --- /dev/null +++ b/erpnext/erpnext_integrations/doctype/taxjar_nexus/taxjar_nexus.py @@ -0,0 +1,9 @@ +# Copyright (c) 2021, Frappe Technologies Pvt. Ltd. and contributors +# For license information, please see license.txt + +# import frappe +from frappe.model.document import Document + + +class TaxJarNexus(Document): + pass diff --git a/erpnext/regional/united_states/product_tax_category_data.json b/erpnext/erpnext_integrations/doctype/taxjar_settings/product_tax_category_data.json similarity index 100% rename from erpnext/regional/united_states/product_tax_category_data.json rename to erpnext/erpnext_integrations/doctype/taxjar_settings/product_tax_category_data.json diff --git a/erpnext/erpnext_integrations/doctype/taxjar_settings/taxjar_settings.js b/erpnext/erpnext_integrations/doctype/taxjar_settings/taxjar_settings.js index 62d5709f51f..2925db82e33 100644 --- a/erpnext/erpnext_integrations/doctype/taxjar_settings/taxjar_settings.js +++ b/erpnext/erpnext_integrations/doctype/taxjar_settings/taxjar_settings.js @@ -5,5 +5,33 @@ frappe.ui.form.on('TaxJar Settings', { is_sandbox: (frm) => { frm.toggle_reqd("api_key", !frm.doc.is_sandbox); frm.toggle_reqd("sandbox_api_key", frm.doc.is_sandbox); - } + }, + + on_load: (frm) => { + frm.set_query('shipping_account_head', function() { + return { + filters: { + 'company': frm.doc.company + } + }; + }); + frm.set_query('tax_account_head', function() { + return { + filters: { + 'company': frm.doc.company + } + }; + }); + }, + + refresh: (frm) => { + frm.add_custom_button(__('Update Nexus List'), function() { + frm.call({ + doc: frm.doc, + method: 'update_nexus_list' + }); + }); + }, + + }); diff --git a/erpnext/erpnext_integrations/doctype/taxjar_settings/taxjar_settings.json b/erpnext/erpnext_integrations/doctype/taxjar_settings/taxjar_settings.json index c0d60f7a317..23ccb7e4dac 100644 --- a/erpnext/erpnext_integrations/doctype/taxjar_settings/taxjar_settings.json +++ b/erpnext/erpnext_integrations/doctype/taxjar_settings/taxjar_settings.json @@ -6,17 +6,22 @@ "editable_grid": 1, "engine": "InnoDB", "field_order": [ - "is_sandbox", "taxjar_calculate_tax", + "is_sandbox", "taxjar_create_transactions", "credentials", "api_key", "cb_keys", "sandbox_api_key", "configuration", + "company", + "column_break_10", "tax_account_head", "configuration_cb", - "shipping_account_head" + "shipping_account_head", + "section_break_12", + "nexus_address", + "nexus" ], "fields": [ { @@ -54,6 +59,7 @@ }, { "default": "0", + "depends_on": "taxjar_calculate_tax", "fieldname": "is_sandbox", "fieldtype": "Check", "label": "Sandbox Mode" @@ -63,12 +69,9 @@ "fieldtype": "Password", "label": "Sandbox API Key" }, - { - "fieldname": "configuration_cb", - "fieldtype": "Column Break" - }, { "default": "0", + "depends_on": "taxjar_calculate_tax", "fieldname": "taxjar_create_transactions", "fieldtype": "Check", "label": "Create TaxJar Transaction" @@ -82,11 +85,42 @@ { "fieldname": "cb_keys", "fieldtype": "Column Break" + }, + { + "fieldname": "section_break_12", + "fieldtype": "Section Break", + "label": "Nexus List" + }, + { + "fieldname": "nexus_address", + "fieldtype": "HTML", + "label": "Nexus Address" + }, + { + "fieldname": "nexus", + "fieldtype": "Table", + "label": "Nexus", + "options": "TaxJar Nexus", + "read_only": 1 + }, + { + "fieldname": "configuration_cb", + "fieldtype": "Column Break" + }, + { + "fieldname": "column_break_10", + "fieldtype": "Column Break" + }, + { + "fieldname": "company", + "fieldtype": "Link", + "label": "Company", + "options": "Company" } ], "issingle": 1, "links": [], - "modified": "2020-04-30 04:38:03.311089", + "modified": "2021-11-08 18:02:29.232090", "modified_by": "Administrator", "module": "ERPNext Integrations", "name": "TaxJar Settings", diff --git a/erpnext/erpnext_integrations/doctype/taxjar_settings/taxjar_settings.py b/erpnext/erpnext_integrations/doctype/taxjar_settings/taxjar_settings.py index 9dd481747ec..b9f24b65b38 100644 --- a/erpnext/erpnext_integrations/doctype/taxjar_settings/taxjar_settings.py +++ b/erpnext/erpnext_integrations/doctype/taxjar_settings/taxjar_settings.py @@ -1,12 +1,99 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2020, Frappe Technologies Pvt. Ltd. and contributors # For license information, please see license.txt -from __future__ import unicode_literals -# import frappe +import json +import os + +import frappe +from frappe.custom.doctype.custom_field.custom_field import create_custom_fields from frappe.model.document import Document +from frappe.permissions import add_permission, update_permission_property + +from erpnext.erpnext_integrations.taxjar_integration import get_client class TaxJarSettings(Document): - pass + + def on_update(self): + TAXJAR_CREATE_TRANSACTIONS = frappe.db.get_single_value("TaxJar Settings", "taxjar_create_transactions") + TAXJAR_CALCULATE_TAX = frappe.db.get_single_value("TaxJar Settings", "taxjar_calculate_tax") + TAXJAR_SANDBOX_MODE = frappe.db.get_single_value("TaxJar Settings", "is_sandbox") + + fields_already_exist = frappe.db.exists('Custom Field', {'dt': ('in', ['Item','Sales Invoice Item']), 'fieldname':'product_tax_category'}) + fields_hidden = frappe.get_value('Custom Field', {'dt': ('in', ['Sales Invoice Item'])}, 'hidden') + + if (TAXJAR_CREATE_TRANSACTIONS or TAXJAR_CALCULATE_TAX or TAXJAR_SANDBOX_MODE): + if not fields_already_exist: + add_product_tax_categories() + make_custom_fields() + add_permissions() + frappe.enqueue('erpnext.regional.united_states.setup.add_product_tax_categories', now=False) + + elif fields_already_exist and fields_hidden: + toggle_tax_category_fields(hidden='0') + + elif fields_already_exist: + toggle_tax_category_fields(hidden='1') + + def validate(self): + self.calculate_taxes_validation_for_create_transactions() + + @frappe.whitelist() + def update_nexus_list(self): + client = get_client() + nexus = client.nexus_regions() + + new_nexus_list = [frappe._dict(address) for address in nexus] + + self.set('nexus', []) + self.set('nexus', new_nexus_list) + self.save() + + def calculate_taxes_validation_for_create_transactions(self): + if not self.taxjar_calculate_tax and (self.taxjar_create_transactions or self.is_sandbox): + frappe.throw(frappe._('Before enabling Create Transaction or Sandbox Mode, you need to check the Enable Tax Calculation box')) + + +def toggle_tax_category_fields(hidden): + frappe.set_value('Custom Field', {'dt':'Sales Invoice Item', 'fieldname':'product_tax_category'}, 'hidden', hidden) + frappe.set_value('Custom Field', {'dt':'Item', 'fieldname':'product_tax_category'}, 'hidden', hidden) + + +def add_product_tax_categories(): + with open(os.path.join(os.path.dirname(__file__), 'product_tax_category_data.json'), 'r') as f: + tax_categories = json.loads(f.read()) + create_tax_categories(tax_categories['categories']) + +def create_tax_categories(data): + for d in data: + if not frappe.db.exists('Product Tax Category',{'product_tax_code':d.get('product_tax_code')}): + tax_category = frappe.new_doc('Product Tax Category') + tax_category.description = d.get("description") + tax_category.product_tax_code = d.get("product_tax_code") + tax_category.category_name = d.get("name") + tax_category.db_insert() + +def make_custom_fields(update=True): + custom_fields = { + 'Sales Invoice Item': [ + dict(fieldname='product_tax_category', fieldtype='Link', insert_after='description', options='Product Tax Category', + label='Product Tax Category', fetch_from='item_code.product_tax_category'), + dict(fieldname='tax_collectable', fieldtype='Currency', insert_after='net_amount', + label='Tax Collectable', read_only=1, options='currency'), + dict(fieldname='taxable_amount', fieldtype='Currency', insert_after='tax_collectable', + label='Taxable Amount', read_only=1, options='currency') + ], + 'Item': [ + dict(fieldname='product_tax_category', fieldtype='Link', insert_after='item_group', options='Product Tax Category', + label='Product Tax Category') + ] + } + create_custom_fields(custom_fields, update=update) + +def add_permissions(): + doctype = "Product Tax Category" + for role in ('Accounts Manager', 'Accounts User', 'System Manager','Item Manager', 'Stock Manager'): + add_permission(doctype, role, 0) + update_permission_property(doctype, role, 0, 'write', 1) + update_permission_property(doctype, role, 0, 'create', 1) diff --git a/erpnext/erpnext_integrations/doctype/taxjar_settings/test_taxjar_settings.py b/erpnext/erpnext_integrations/doctype/taxjar_settings/test_taxjar_settings.py index c871b05642b..d6f8eea1e0e 100644 --- a/erpnext/erpnext_integrations/doctype/taxjar_settings/test_taxjar_settings.py +++ b/erpnext/erpnext_integrations/doctype/taxjar_settings/test_taxjar_settings.py @@ -1,7 +1,5 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2020, Frappe Technologies Pvt. Ltd. and Contributors # See license.txt -from __future__ import unicode_literals # import frappe import unittest diff --git a/erpnext/erpnext_integrations/doctype/woocommerce_settings/test_woocommerce_settings.py b/erpnext/erpnext_integrations/doctype/woocommerce_settings/test_woocommerce_settings.py index 3d184584361..9945823bf73 100644 --- a/erpnext/erpnext_integrations/doctype/woocommerce_settings/test_woocommerce_settings.py +++ b/erpnext/erpnext_integrations/doctype/woocommerce_settings/test_woocommerce_settings.py @@ -1,7 +1,5 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2018, Frappe Technologies Pvt. Ltd. and Contributors # See license.txt -from __future__ import unicode_literals import unittest diff --git a/erpnext/erpnext_integrations/doctype/woocommerce_settings/woocommerce_settings.py b/erpnext/erpnext_integrations/doctype/woocommerce_settings/woocommerce_settings.py index 2e15fab0d3f..8da52f49f1c 100644 --- a/erpnext/erpnext_integrations/doctype/woocommerce_settings/woocommerce_settings.py +++ b/erpnext/erpnext_integrations/doctype/woocommerce_settings/woocommerce_settings.py @@ -1,8 +1,6 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2018, Frappe Technologies Pvt. Ltd. and contributors # For license information, please see license.txt -from __future__ import unicode_literals import frappe from frappe import _ diff --git a/erpnext/erpnext_integrations/stripe_integration.py b/erpnext/erpnext_integrations/stripe_integration.py index f0315eb7eef..502cb5f00a4 100644 --- a/erpnext/erpnext_integrations/stripe_integration.py +++ b/erpnext/erpnext_integrations/stripe_integration.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2018, Frappe Technologies Pvt. Ltd. and contributors # For license information, please see license.txt diff --git a/erpnext/erpnext_integrations/taxjar_integration.py b/erpnext/erpnext_integrations/taxjar_integration.py index 870a4ef54cc..a4e21579e32 100644 --- a/erpnext/erpnext_integrations/taxjar_integration.py +++ b/erpnext/erpnext_integrations/taxjar_integration.py @@ -4,9 +4,9 @@ import frappe import taxjar from frappe import _ from frappe.contacts.doctype.address.address import get_company_address -from frappe.utils import cint +from frappe.utils import cint, flt -from erpnext import get_default_company +from erpnext import get_default_company, get_region TAX_ACCOUNT_HEAD = frappe.db.get_single_value("TaxJar Settings", "tax_account_head") SHIP_ACCOUNT_HEAD = frappe.db.get_single_value("TaxJar Settings", "shipping_account_head") @@ -21,6 +21,7 @@ SUPPORTED_STATE_CODES = ['AL', 'AK', 'AZ', 'AR', 'CA', 'CO', 'CT', 'DE', 'DC', ' 'TN', 'TX', 'UT', 'VT', 'VA', 'WA', 'WV', 'WI', 'WY'] + def get_client(): taxjar_settings = frappe.get_single("TaxJar Settings") @@ -103,7 +104,7 @@ def get_tax_data(doc): shipping = sum([tax.tax_amount for tax in doc.taxes if tax.account_head == SHIP_ACCOUNT_HEAD]) - line_items = [get_line_item_dict(item) for item in doc.items] + line_items = [get_line_item_dict(item, doc.docstatus) for item in doc.items] if from_shipping_state not in SUPPORTED_STATE_CODES: from_shipping_state = get_state_code(from_address, 'Company') @@ -139,18 +140,28 @@ def get_state_code(address, location): return state_code -def get_line_item_dict(item): - return dict( +def get_line_item_dict(item, docstatus): + tax_dict = dict( id = item.get('idx'), quantity = item.get('qty'), unit_price = item.get('rate'), product_tax_code = item.get('product_tax_category') ) + if docstatus == 1: + tax_dict.update({ + 'sales_tax':item.get('tax_collectable') + }) + + return tax_dict + def set_sales_tax(doc, method): if not TAXJAR_CALCULATE_TAX: return + if get_region(doc.company) != 'United States': + return + if not doc.items: return @@ -164,6 +175,9 @@ def set_sales_tax(doc, method): setattr(doc, "taxes", [tax for tax in doc.taxes if tax.account_head != TAX_ACCOUNT_HEAD]) return + # check if delivering within a nexus + check_for_nexus(doc, tax_dict) + tax_data = validate_tax_request(tax_dict) if tax_data is not None: if not tax_data.amount_to_collect: @@ -191,6 +205,17 @@ def set_sales_tax(doc, method): doc.run_method("calculate_taxes_and_totals") +def check_for_nexus(doc, tax_dict): + if not frappe.db.get_value('TaxJar Nexus', {'region_code': tax_dict["to_state"]}): + for item in doc.get("items"): + item.tax_collectable = flt(0) + item.taxable_amount = flt(0) + + for tax in doc.taxes: + if tax.account_head == TAX_ACCOUNT_HEAD: + doc.taxes.remove(tax) + return + def check_sales_tax_exemption(doc): # if the party is exempt from sales tax, then set all tax account heads to zero sales_tax_exempted = hasattr(doc, "exempt_from_sales_tax") and doc.exempt_from_sales_tax \ @@ -241,7 +266,7 @@ def get_shipping_address_details(doc): if doc.shipping_address_name: shipping_address = frappe.get_doc("Address", doc.shipping_address_name) elif doc.customer_address: - shipping_address = frappe.get_doc("Address", doc.customer_address_name) + shipping_address = frappe.get_doc("Address", doc.customer_address) else: shipping_address = get_company_address_details(doc) diff --git a/erpnext/erpnext_integrations/utils.py b/erpnext/erpnext_integrations/utils.py index bb5c0c2dd10..d922d875fdd 100644 --- a/erpnext/erpnext_integrations/utils.py +++ b/erpnext/erpnext_integrations/utils.py @@ -1,5 +1,3 @@ -from __future__ import unicode_literals - import base64 import hashlib import hmac @@ -25,7 +23,6 @@ def validate_webhooks_request(doctype, hmac_key, secret_key='secret'): ) if frappe.request.data and \ - frappe.get_request_header(hmac_key) and \ not sig == bytes(frappe.get_request_header(hmac_key).encode()): frappe.throw(_("Unverified Webhook Data")) frappe.set_user(settings.modified_by) diff --git a/erpnext/erpnext_integrations/workspace/erpnext_integrations/erpnext_integrations.json b/erpnext/erpnext_integrations/workspace/erpnext_integrations/erpnext_integrations.json index 9f9204a78d8..8e4f92791ab 100644 --- a/erpnext/erpnext_integrations/workspace/erpnext_integrations/erpnext_integrations.json +++ b/erpnext/erpnext_integrations/workspace/erpnext_integrations/erpnext_integrations.json @@ -1,20 +1,13 @@ { - "category": "", "charts": [], "content": "[{\"type\": \"header\", \"data\": {\"text\": \"Reports & Masters\", \"level\": 4, \"col\": 12}}, {\"type\": \"card\", \"data\": {\"card_name\": \"Marketplace\", \"col\": 4}}, {\"type\": \"card\", \"data\": {\"card_name\": \"Payments\", \"col\": 4}}, {\"type\": \"card\", \"data\": {\"card_name\": \"Settings\", \"col\": 4}}]", "creation": "2020-08-20 19:30:48.138801", - "developer_mode_only": 0, - "disable_user_customization": 0, "docstatus": 0, "doctype": "Workspace", - "extends": "", - "extends_another_page": 0, "for_user": "", "hide_custom": 0, "icon": "integration", "idx": 0, - "is_default": 0, - "is_standard": 0, "label": "ERPNext Integrations", "links": [ { @@ -119,15 +112,12 @@ "type": "Link" } ], - "modified": "2021-08-05 12:15:58.740246", + "modified": "2021-08-05 12:15:58.740247", "modified_by": "Administrator", "module": "ERPNext Integrations", "name": "ERPNext Integrations", - "onboarding": "", "owner": "Administrator", "parent_page": "", - "pin_to_bottom": 0, - "pin_to_top": 0, "public": 1, "restrict_to_domain": "", "roles": [], diff --git a/erpnext/erpnext_integrations/workspace/erpnext_integrations_settings/erpnext_integrations_settings.json b/erpnext/erpnext_integrations/workspace/erpnext_integrations_settings/erpnext_integrations_settings.json index fd4afb85fdd..5efafd67fe8 100644 --- a/erpnext/erpnext_integrations/workspace/erpnext_integrations_settings/erpnext_integrations_settings.json +++ b/erpnext/erpnext_integrations/workspace/erpnext_integrations_settings/erpnext_integrations_settings.json @@ -1,20 +1,13 @@ { - "category": "", "charts": [], "content": "[{\"type\": \"header\", \"data\": {\"text\": \"Reports & Masters\", \"level\": 4, \"col\": 12}}, {\"type\": \"card\", \"data\": {\"card_name\": \"Integrations Settings\", \"col\": 4}}]", "creation": "2020-07-31 10:38:54.021237", - "developer_mode_only": 0, - "disable_user_customization": 0, "docstatus": 0, "doctype": "Workspace", - "extends": "", - "extends_another_page": 0, "for_user": "", "hide_custom": 0, "icon": "setting", "idx": 0, - "is_default": 0, - "is_standard": 0, "label": "ERPNext Integrations Settings", "links": [ { @@ -36,17 +29,6 @@ "onboard": 0, "type": "Link" }, - { - "dependencies": "", - "hidden": 0, - "is_query_report": 0, - "label": "Shopify Settings", - "link_count": 0, - "link_to": "Shopify Settings", - "link_type": "DocType", - "onboard": 0, - "type": "Link" - }, { "dependencies": "", "hidden": 0, @@ -81,19 +63,16 @@ "type": "Link" } ], - "modified": "2021-08-05 12:15:58.951704", + "modified": "2021-11-23 04:30:33.106991", "modified_by": "Administrator", "module": "ERPNext Integrations", "name": "ERPNext Integrations Settings", - "onboarding": "", "owner": "Administrator", "parent_page": "", - "pin_to_bottom": 0, - "pin_to_top": 0, "public": 1, "restrict_to_domain": "", "roles": [], "sequence_id": 11, "shortcuts": [], "title": "ERPNext Integrations Settings" -} +} \ No newline at end of file diff --git a/erpnext/exceptions.py b/erpnext/exceptions.py index 9c6b13f8035..8d6f13a77e6 100644 --- a/erpnext/exceptions.py +++ b/erpnext/exceptions.py @@ -1,5 +1,3 @@ -from __future__ import unicode_literals - import frappe diff --git a/erpnext/healthcare/dashboard_chart/clinical_procedures/clinical_procedures.json b/erpnext/healthcare/dashboard_chart/clinical_procedures/clinical_procedures.json deleted file mode 100644 index 68035281561..00000000000 --- a/erpnext/healthcare/dashboard_chart/clinical_procedures/clinical_procedures.json +++ /dev/null @@ -1,26 +0,0 @@ -{ - "chart_name": "Clinical Procedures", - "chart_type": "Group By", - "creation": "2020-07-14 18:17:54.601236", - "docstatus": 0, - "doctype": "Dashboard Chart", - "document_type": "Clinical Procedure", - "dynamic_filters_json": "[[\"Clinical Procedure\",\"company\",\"=\",\"frappe.defaults.get_user_default(\\\"Company\\\")\"]]", - "filters_json": "[[\"Clinical Procedure\",\"docstatus\",\"=\",\"1\",false]]", - "group_by_based_on": "procedure_template", - "group_by_type": "Count", - "idx": 0, - "is_public": 1, - "is_standard": 1, - "last_synced_on": "2021-01-30 21:03:30.086891", - "modified": "2021-02-01 13:36:04.469863", - "modified_by": "Administrator", - "module": "Healthcare", - "name": "Clinical Procedures", - "number_of_groups": 0, - "owner": "Administrator", - "timeseries": 0, - "type": "Bar", - "use_report_chart": 0, - "y_axis": [] -} \ No newline at end of file diff --git a/erpnext/healthcare/dashboard_chart/clinical_procedures_status/clinical_procedures_status.json b/erpnext/healthcare/dashboard_chart/clinical_procedures_status/clinical_procedures_status.json deleted file mode 100644 index dae9db19b8d..00000000000 --- a/erpnext/healthcare/dashboard_chart/clinical_procedures_status/clinical_procedures_status.json +++ /dev/null @@ -1,26 +0,0 @@ -{ - "chart_name": "Clinical Procedure Status", - "chart_type": "Group By", - "creation": "2020-07-14 18:17:54.654325", - "docstatus": 0, - "doctype": "Dashboard Chart", - "document_type": "Clinical Procedure", - "dynamic_filters_json": "[[\"Clinical Procedure\",\"company\",\"=\",\"frappe.defaults.get_user_default(\\\"Company\\\")\"]]", - "filters_json": "[[\"Clinical Procedure\",\"docstatus\",\"=\",\"1\",false]]", - "group_by_based_on": "status", - "group_by_type": "Count", - "idx": 0, - "is_public": 1, - "is_standard": 1, - "last_synced_on": "2021-02-01 13:36:38.787783", - "modified": "2021-02-01 13:37:18.718275", - "modified_by": "Administrator", - "module": "Healthcare", - "name": "Clinical Procedures Status", - "number_of_groups": 0, - "owner": "Administrator", - "timeseries": 0, - "type": "Bar", - "use_report_chart": 0, - "y_axis": [] -} \ No newline at end of file diff --git a/erpnext/healthcare/dashboard_chart/department_wise_patient_appointments/department_wise_patient_appointments.json b/erpnext/healthcare/dashboard_chart/department_wise_patient_appointments/department_wise_patient_appointments.json deleted file mode 100644 index b24bb345ac4..00000000000 --- a/erpnext/healthcare/dashboard_chart/department_wise_patient_appointments/department_wise_patient_appointments.json +++ /dev/null @@ -1,25 +0,0 @@ -{ - "chart_name": "Department wise Patient Appointments", - "chart_type": "Custom", - "creation": "2020-07-17 11:25:37.190130", - "custom_options": "{\"colors\": [\"#7CD5FA\", \"#5F62F6\", \"#7544E2\", \"#EE5555\"], \"barOptions\": {\"stacked\": 1}, \"height\": 300}", - "docstatus": 0, - "doctype": "Dashboard Chart", - "dynamic_filters_json": "{\"company\":\"frappe.defaults.get_user_default(\\\"Company\\\")\"}", - "filters_json": "{}", - "idx": 0, - "is_public": 1, - "is_standard": 1, - "last_synced_on": "2020-07-22 15:32:05.827566", - "modified": "2020-07-22 15:35:12.798035", - "modified_by": "Administrator", - "module": "Healthcare", - "name": "Department wise Patient Appointments", - "number_of_groups": 0, - "owner": "Administrator", - "source": "Department wise Patient Appointments", - "timeseries": 0, - "type": "Bar", - "use_report_chart": 0, - "y_axis": [] -} \ No newline at end of file diff --git a/erpnext/healthcare/dashboard_chart/diagnoses/diagnoses.json b/erpnext/healthcare/dashboard_chart/diagnoses/diagnoses.json deleted file mode 100644 index 82145d60248..00000000000 --- a/erpnext/healthcare/dashboard_chart/diagnoses/diagnoses.json +++ /dev/null @@ -1,26 +0,0 @@ -{ - "chart_name": "Diagnoses", - "chart_type": "Group By", - "creation": "2020-07-14 18:17:54.705698", - "docstatus": 0, - "doctype": "Dashboard Chart", - "document_type": "Patient Encounter Diagnosis", - "dynamic_filters_json": "", - "filters_json": "[]", - "group_by_based_on": "diagnosis", - "group_by_type": "Count", - "idx": 0, - "is_public": 1, - "is_standard": 1, - "last_synced_on": "2021-01-30 21:03:33.729487", - "modified": "2021-02-01 13:34:57.385335", - "modified_by": "Administrator", - "module": "Healthcare", - "name": "Diagnoses", - "number_of_groups": 0, - "owner": "Administrator", - "timeseries": 0, - "type": "Bar", - "use_report_chart": 0, - "y_axis": [] -} \ No newline at end of file diff --git a/erpnext/healthcare/dashboard_chart/in_patient_status/in_patient_status.json b/erpnext/healthcare/dashboard_chart/in_patient_status/in_patient_status.json deleted file mode 100644 index 77b47c9e155..00000000000 --- a/erpnext/healthcare/dashboard_chart/in_patient_status/in_patient_status.json +++ /dev/null @@ -1,26 +0,0 @@ -{ - "chart_name": "In-Patient Status", - "chart_type": "Group By", - "creation": "2020-07-14 18:17:54.629199", - "docstatus": 0, - "doctype": "Dashboard Chart", - "document_type": "Inpatient Record", - "dynamic_filters_json": "[[\"Inpatient Record\",\"company\",\"=\",\"frappe.defaults.get_user_default(\\\"Company\\\")\"]]", - "filters_json": "[]", - "group_by_based_on": "status", - "group_by_type": "Count", - "idx": 0, - "is_public": 1, - "is_standard": 1, - "last_synced_on": "2020-07-22 13:22:46.792131", - "modified": "2020-07-22 13:33:16.008150", - "modified_by": "Administrator", - "module": "Healthcare", - "name": "In-Patient Status", - "number_of_groups": 0, - "owner": "Administrator", - "timeseries": 0, - "type": "Bar", - "use_report_chart": 0, - "y_axis": [] -} \ No newline at end of file diff --git a/erpnext/healthcare/dashboard_chart/lab_tests/lab_tests.json b/erpnext/healthcare/dashboard_chart/lab_tests/lab_tests.json deleted file mode 100644 index 70293b158ed..00000000000 --- a/erpnext/healthcare/dashboard_chart/lab_tests/lab_tests.json +++ /dev/null @@ -1,26 +0,0 @@ -{ - "chart_name": "Lab Tests", - "chart_type": "Group By", - "creation": "2020-07-14 18:17:54.574903", - "docstatus": 0, - "doctype": "Dashboard Chart", - "document_type": "Lab Test", - "dynamic_filters_json": "[[\"Lab Test\",\"company\",\"=\",\"frappe.defaults.get_user_default(\\\"Company\\\")\"]]", - "filters_json": "[[\"Lab Test\",\"docstatus\",\"=\",\"1\",false]]", - "group_by_based_on": "template", - "group_by_type": "Count", - "idx": 0, - "is_public": 1, - "is_standard": 1, - "last_synced_on": "2021-01-30 21:03:28.272914", - "modified": "2021-02-01 13:36:08.391433", - "modified_by": "Administrator", - "module": "Healthcare", - "name": "Lab Tests", - "number_of_groups": 0, - "owner": "Administrator", - "timeseries": 0, - "type": "Bar", - "use_report_chart": 0, - "y_axis": [] -} \ No newline at end of file diff --git a/erpnext/healthcare/dashboard_chart/patient_appointments/patient_appointments.json b/erpnext/healthcare/dashboard_chart/patient_appointments/patient_appointments.json deleted file mode 100644 index 19bfb7256fc..00000000000 --- a/erpnext/healthcare/dashboard_chart/patient_appointments/patient_appointments.json +++ /dev/null @@ -1,27 +0,0 @@ -{ - "based_on": "appointment_datetime", - "chart_name": "Patient Appointments", - "chart_type": "Count", - "creation": "2020-07-14 18:17:54.525082", - "docstatus": 0, - "doctype": "Dashboard Chart", - "document_type": "Patient Appointment", - "dynamic_filters_json": "[[\"Patient Appointment\",\"company\",\"=\",\"frappe.defaults.get_user_default(\\\"Company\\\")\"]]", - "filters_json": "[[\"Patient Appointment\",\"status\",\"!=\",\"Cancelled\",false]]", - "idx": 0, - "is_public": 0, - "is_standard": 1, - "last_synced_on": "2020-07-22 13:22:46.830491", - "modified": "2020-07-22 13:38:02.254190", - "modified_by": "Administrator", - "module": "Healthcare", - "name": "Patient Appointments", - "number_of_groups": 0, - "owner": "Administrator", - "time_interval": "Daily", - "timeseries": 1, - "timespan": "Last Month", - "type": "Line", - "use_report_chart": 0, - "y_axis": [] -} \ No newline at end of file diff --git a/erpnext/healthcare/dashboard_chart/symptoms/symptoms.json b/erpnext/healthcare/dashboard_chart/symptoms/symptoms.json deleted file mode 100644 index 65e5472aa10..00000000000 --- a/erpnext/healthcare/dashboard_chart/symptoms/symptoms.json +++ /dev/null @@ -1,26 +0,0 @@ -{ - "chart_name": "Symptoms", - "chart_type": "Group By", - "creation": "2020-07-14 18:17:54.680852", - "docstatus": 0, - "doctype": "Dashboard Chart", - "document_type": "Patient Encounter Symptom", - "dynamic_filters_json": "", - "filters_json": "[]", - "group_by_based_on": "complaint", - "group_by_type": "Count", - "idx": 0, - "is_public": 1, - "is_standard": 1, - "last_synced_on": "2021-01-30 21:03:32.067473", - "modified": "2021-02-01 13:35:30.953718", - "modified_by": "Administrator", - "module": "Healthcare", - "name": "Symptoms", - "number_of_groups": 0, - "owner": "Administrator", - "timeseries": 0, - "type": "Bar", - "use_report_chart": 0, - "y_axis": [] -} \ No newline at end of file diff --git a/erpnext/healthcare/dashboard_chart_source/department_wise_patient_appointments/department_wise_patient_appointments.js b/erpnext/healthcare/dashboard_chart_source/department_wise_patient_appointments/department_wise_patient_appointments.js deleted file mode 100644 index e494489d21a..00000000000 --- a/erpnext/healthcare/dashboard_chart_source/department_wise_patient_appointments/department_wise_patient_appointments.js +++ /dev/null @@ -1,14 +0,0 @@ -frappe.provide('frappe.dashboards.chart_sources'); - -frappe.dashboards.chart_sources["Department wise Patient Appointments"] = { - method: "erpnext.healthcare.dashboard_chart_source.department_wise_patient_appointments.department_wise_patient_appointments.get", - filters: [ - { - fieldname: "company", - label: __("Company"), - fieldtype: "Link", - options: "Company", - default: frappe.defaults.get_user_default("Company") - } - ] -}; diff --git a/erpnext/healthcare/dashboard_chart_source/department_wise_patient_appointments/department_wise_patient_appointments.json b/erpnext/healthcare/dashboard_chart_source/department_wise_patient_appointments/department_wise_patient_appointments.json deleted file mode 100644 index 00301ef2c36..00000000000 --- a/erpnext/healthcare/dashboard_chart_source/department_wise_patient_appointments/department_wise_patient_appointments.json +++ /dev/null @@ -1,13 +0,0 @@ -{ - "creation": "2020-05-18 19:18:42.571045", - "docstatus": 0, - "doctype": "Dashboard Chart Source", - "idx": 0, - "modified": "2020-05-18 19:18:42.571045", - "modified_by": "Administrator", - "module": "Healthcare", - "name": "Department wise Patient Appointments", - "owner": "Administrator", - "source_name": "Department wise Patient Appointments", - "timeseries": 0 -} \ No newline at end of file diff --git a/erpnext/healthcare/dashboard_chart_source/department_wise_patient_appointments/department_wise_patient_appointments.py b/erpnext/healthcare/dashboard_chart_source/department_wise_patient_appointments/department_wise_patient_appointments.py deleted file mode 100644 index 9c71ce86ac4..00000000000 --- a/erpnext/healthcare/dashboard_chart_source/department_wise_patient_appointments/department_wise_patient_appointments.py +++ /dev/null @@ -1,74 +0,0 @@ -# Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors -# License: GNU General Public License v3. See license.txt - -from __future__ import unicode_literals - -import frappe -from frappe.utils.dashboard import cache_source - - -@frappe.whitelist() -@cache_source -def get(chart_name = None, chart = None, no_cache = None, filters = None, from_date = None, - to_date = None, timespan = None, time_interval = None, heatmap_year = None): - if chart_name: - chart = frappe.get_doc('Dashboard Chart', chart_name) - else: - chart = frappe._dict(frappe.parse_json(chart)) - - filters = frappe.parse_json(filters) - - data = frappe.db.get_list('Medical Department', fields=['name']) - if not filters: - filters = {} - - status = ['Open', 'Scheduled', 'Closed', 'Cancelled'] - for department in data: - filters['department'] = department.name - department['total_appointments'] = frappe.db.count('Patient Appointment', filters=filters) - - for entry in status: - filters['status'] = entry - department[frappe.scrub(entry)] = frappe.db.count('Patient Appointment', filters=filters) - filters.pop('status') - - sorted_department_map = sorted(data, key = lambda i: i['total_appointments'], reverse=True) - - if len(sorted_department_map) > 10: - sorted_department_map = sorted_department_map[:10] - - labels = [] - open_appointments = [] - scheduled = [] - closed = [] - cancelled = [] - - for department in sorted_department_map: - labels.append(department.name) - open_appointments.append(department.open) - scheduled.append(department.scheduled) - closed.append(department.closed) - cancelled.append(department.cancelled) - - return { - 'labels': labels, - 'datasets': [ - { - 'name': 'Open', - 'values': open_appointments - }, - { - 'name': 'Scheduled', - 'values': scheduled - }, - { - 'name': 'Closed', - 'values': closed - }, - { - 'name': 'Cancelled', - 'values': cancelled - } - ], - 'type': 'bar' - } diff --git a/erpnext/healthcare/desk_page/healthcare/healthcare.json b/erpnext/healthcare/desk_page/healthcare/healthcare.json deleted file mode 100644 index af601f3eb2e..00000000000 --- a/erpnext/healthcare/desk_page/healthcare/healthcare.json +++ /dev/null @@ -1,122 +0,0 @@ -{ - "cards": [ - { - "hidden": 0, - "label": "Masters", - "links": "[\n\t{\n\t\t\"type\": \"doctype\",\n\t\t\"name\": \"Patient\",\n\t\t\"label\": \"Patient\",\n\t\t\"onboard\": 1\n\t},\n\t{\n\t\t\"type\": \"doctype\",\n\t\t\"name\": \"Healthcare Practitioner\",\n\t\t\"label\":\"Healthcare Practitioner\",\n\t\t\"onboard\": 1\n\t},\n\t{\n\t\t\"type\": \"doctype\",\n\t\t\"name\": \"Practitioner Schedule\",\n\t\t\"label\": \"Practitioner Schedule\",\n\t\t\"onboard\": 1\n\t},\n\t{\n\t\t\"type\": \"doctype\",\n\t\t\"name\": \"Medical Department\",\n\t\t\"label\": \"Medical Department\"\n\t},\n\t{\n\t\t\"type\": \"doctype\",\n\t\t\"name\": \"Healthcare Service Unit Type\",\n\t\t\"label\": \"Healthcare Service Unit Type\"\n\t},\n\t{\n\t\t\"type\": \"doctype\",\n\t\t\"name\": \"Healthcare Service Unit\",\n\t\t\"label\": \"Healthcare Service Unit\"\n\t},\n\t{\n\t\t\"type\": \"doctype\",\n\t\t\"name\": \"Medical Code Standard\",\n\t\t\"label\": \"Medical Code Standard\"\n\t},\n\t{\n\t\t\"type\": \"doctype\",\n\t\t\"name\": \"Medical Code\",\n\t\t\"label\": \"Medical Code\"\n\t}\n]" - }, - { - "hidden": 0, - "label": "Consultation Setup", - "links": "[\n\t{\n\t\t\"type\": \"doctype\",\n\t\t\"name\": \"Appointment Type\",\n\t\t\"label\": \"Appointment Type\"\n },\n\t{\n\t\t\"type\": \"doctype\",\n\t\t\"name\": \"Clinical Procedure Template\",\n\t\t\"label\": \"Clinical Procedure Template\"\n\t},\n\t{\n\t\t\"type\": \"doctype\",\n\t\t\"name\": \"Prescription Dosage\",\n\t\t\"label\": \"Prescription Dosage\"\n\t},\n\t{\n\t\t\"type\": \"doctype\",\n\t\t\"name\": \"Prescription Duration\",\n\t\t\"label\": \"Prescription Duration\"\n\t},\n\t{\n\t \"type\": \"doctype\",\n\t\t\"name\": \"Antibiotic\",\n\t\t\"label\": \"Antibiotic\"\n\t}\n]" - }, - { - "hidden": 0, - "label": "Consultation", - "links": "[\n\t{\n\t\t\"type\": \"doctype\",\n\t\t\"name\": \"Patient Appointment\",\n\t\t\"label\": \"Patient Appointment\"\n\t},\n\t{\n\t\t\"type\": \"doctype\",\n\t\t\"name\": \"Clinical Procedure\",\n\t\t\"label\": \"Clinical Procedure\"\n\t},\n\t{\n\t\t\"type\": \"doctype\",\n\t\t\"name\": \"Patient Encounter\",\n\t\t\"label\": \"Patient Encounter\"\n\t},\n\t{\n\t\t\"type\": \"doctype\",\n\t\t\"name\": \"Vital Signs\",\n\t\t\"label\": \"Vital Signs\"\n\t},\n\t{\n\t\t\"type\": \"doctype\",\n\t\t\"name\": \"Complaint\",\n\t\t\"label\": \"Complaint\"\n\t},\n\t{\n\t\t\"type\": \"doctype\",\n\t\t\"name\": \"Diagnosis\",\n\t\t\"label\": \"Diagnosis\"\n\t},\n\t{\n\t\t\"type\": \"doctype\",\n\t\t\"name\": \"Fee Validity\",\n\t\t\"label\": \"Fee Validity\"\n\t}\n]" - }, - { - "hidden": 0, - "label": "Settings", - "links": "[\n\t{\n\t\t\"type\": \"doctype\",\n\t\t\"name\": \"Healthcare Settings\",\n\t\t\"label\": \"Healthcare Settings\",\n\t\t\"onboard\": 1\n\t}\n]" - }, - { - "hidden": 0, - "label": "Laboratory Setup", - "links": "[\n\t{\n\t\t\"type\": \"doctype\",\n\t\t\"name\": \"Lab Test Template\",\n\t\t\"label\": \"Lab Test Template\"\n\t},\n\t{\n\t\t\"type\": \"doctype\",\n\t\t\"name\": \"Lab Test Sample\",\n\t\t\"label\": \"Lab Test Sample\"\n\t},\n\t{\n\t\t\"type\": \"doctype\",\n\t\t\"name\": \"Lab Test UOM\",\n\t\t\"label\": \"Lab Test UOM\"\n\t},\n\t{\n\t\t\"type\": \"doctype\",\n\t\t\"name\": \"Sensitivity\",\n\t\t\"label\": \"Sensitivity\"\n\t}\n]" - }, - { - "hidden": 0, - "label": "Laboratory", - "links": "[\n\t{\n\t\t\"type\": \"doctype\",\n\t\t\"name\": \"Lab Test\",\n\t\t\"label\": \"Lab Test\"\n\t},\n\t{\n\t\t\"type\": \"doctype\",\n\t\t\"name\": \"Sample Collection\",\n\t\t\"label\": \"Sample Collection\"\n\t},\n\t{\n\t\t\"type\": \"doctype\",\n\t\t\"name\": \"Dosage Form\",\n\t\t\"label\": \"Dosage Form\"\n\t}\n]" - }, - { - "hidden": 0, - "label": "Inpatient", - "links": "[\n\t{\n\t\t\"type\": \"doctype\",\n\t\t\"name\": \"Inpatient Record\",\n\t\t\"label\": \"Inpatient Record\"\n\t},\n\t{\n\t\t\"type\": \"doctype\",\n\t\t\"name\": \"Inpatient Medication Order\",\n\t\t\"label\": \"Inpatient Medication Order\"\n\t},\n\t{\n\t\t\"type\": \"doctype\",\n\t\t\"name\": \"Inpatient Medication Entry\",\n\t\t\"label\": \"Inpatient Medication Entry\"\n\t}\n]" - }, - { - "hidden": 0, - "label": "Rehabilitation and Physiotherapy", - "links": "[\n {\n\t\t\"type\": \"doctype\",\n\t\t\"name\": \"Exercise Type\",\n\t\t\"label\": \"Exercise Type\",\n\t\t\"onboard\": 1\n\t},\n\t{\n\t\t\"type\": \"doctype\",\n\t\t\"name\": \"Therapy Type\",\n\t\t\"label\": \"Therapy Type\",\n\t\t\"onboard\": 1\n\t},\n\t{\n\t\t\"type\": \"doctype\",\n\t\t\"name\": \"Therapy Plan\",\n\t\t\"label\": \"Therapy Plan\"\n\t},\n\t{\n\t\t\"type\": \"doctype\",\n\t\t\"name\": \"Therapy Session\",\n\t\t\"label\": \"Therapy Session\"\n\t},\n\t{\n\t\t\"type\": \"doctype\",\n\t\t\"name\": \"Patient Assessment Template\",\n\t\t\"label\": \"Patient Assessment Template\"\n\t},\n\t{\n\t\t\"type\": \"doctype\",\n\t\t\"name\": \"Patient Assessment\",\n\t\t\"label\": \"Patient Assessment\"\n\t}\n]" - }, - { - "hidden": 0, - "label": "Records and History", - "links": "[\n\t{\n\t\t\"type\": \"page\",\n\t\t\"name\": \"patient_history\",\n\t\t\"label\": \"Patient History\"\n\t},\n\t{\n\t\t\"type\": \"page\",\n\t\t\"name\": \"patient-progress\",\n\t\t\"label\": \"Patient Progress\"\n\t},\n\t{\n\t\t\"type\": \"doctype\",\n\t\t\"name\": \"Patient Medical Record\",\n\t\t\"label\": \"Patient Medical Record\"\n\t}\n]" - }, - { - "hidden": 0, - "label": "Reports", - "links": "[\n\t{\n\t\t\"type\": \"report\",\n\t\t\"is_query_report\": true,\n\t\t\"name\": \"Patient Appointment Analytics\",\n\t\t\"doctype\": \"Patient Appointment\"\n\t},\n\t{\n\t\t\"type\": \"report\",\n\t\t\"is_query_report\": true,\n\t\t\"name\": \"Lab Test Report\",\n\t\t\"doctype\": \"Lab Test\",\n\t\t\"label\": \"Lab Test Report\"\n\t},\n\t{\n\t\t\"type\": \"report\",\n\t\t\"is_query_report\": true,\n\t\t\"name\": \"Inpatient Medication Orders\",\n\t\t\"doctype\": \"Inpatient Medication Order\",\n\t\t\"label\": \"Inpatient Medication Orders\"\n\t}\n]" - } - ], - "category": "Domains", - "charts": [ - { - "chart_name": "Patient Appointments", - "label": "Patient Appointments" - } - ], - "charts_label": "", - "creation": "2020-03-02 17:23:17.919682", - "developer_mode_only": 0, - "disable_user_customization": 0, - "docstatus": 0, - "doctype": "Desk Page", - "extends_another_page": 0, - "hide_custom": 0, - "idx": 0, - "is_standard": 1, - "label": "Healthcare", - "modified": "2020-11-26 22:09:09.164584", - "modified_by": "Administrator", - "module": "Healthcare", - "name": "Healthcare", - "onboarding": "Healthcare", - "owner": "Administrator", - "pin_to_bottom": 0, - "pin_to_top": 0, - "restrict_to_domain": "Healthcare", - "shortcuts": [ - { - "color": "#ffe8cd", - "format": "{} Open", - "label": "Patient Appointment", - "link_to": "Patient Appointment", - "stats_filter": "{\n \"status\": \"Open\",\n \"company\": [\"like\", '%' + frappe.defaults.get_global_default(\"company\") + '%']\n}", - "type": "DocType" - }, - { - "color": "#ffe8cd", - "format": "{} Active", - "label": "Patient", - "link_to": "Patient", - "stats_filter": "{\n \"status\": \"Active\"\n}", - "type": "DocType" - }, - { - "color": "#cef6d1", - "format": "{} Vacant", - "label": "Healthcare Service Unit", - "link_to": "Healthcare Service Unit", - "stats_filter": "{\n \"occupancy_status\": \"Vacant\",\n \"is_group\": 0,\n \"company\": [\"like\", \"%\" + frappe.defaults.get_global_default(\"company\") + \"%\"]\n}", - "type": "DocType" - }, - { - "label": "Healthcare Practitioner", - "link_to": "Healthcare Practitioner", - "type": "DocType" - }, - { - "label": "Patient History", - "link_to": "patient_history", - "type": "Page" - }, - { - "label": "Dashboard", - "link_to": "Healthcare", - "type": "Dashboard" - } - ] -} \ No newline at end of file diff --git a/erpnext/healthcare/doctype/antibiotic/antibiotic.js b/erpnext/healthcare/doctype/antibiotic/antibiotic.js deleted file mode 100644 index 42e6adb6030..00000000000 --- a/erpnext/healthcare/doctype/antibiotic/antibiotic.js +++ /dev/null @@ -1,5 +0,0 @@ -// Copyright (c) 2017, Frappe Technologies Pvt. Ltd. and contributors -// For license information, please see license.txt - -frappe.ui.form.on('Antibiotic', { -}); diff --git a/erpnext/healthcare/doctype/antibiotic/antibiotic.json b/erpnext/healthcare/doctype/antibiotic/antibiotic.json deleted file mode 100644 index 41a3e318f3d..00000000000 --- a/erpnext/healthcare/doctype/antibiotic/antibiotic.json +++ /dev/null @@ -1,151 +0,0 @@ -{ - "allow_copy": 1, - "allow_events_in_timeline": 0, - "allow_guest_to_view": 0, - "allow_import": 1, - "allow_rename": 1, - "autoname": "field:antibiotic_name", - "beta": 1, - "creation": "2016-02-23 11:11:30.749731", - "custom": 0, - "docstatus": 0, - "doctype": "DocType", - "document_type": "Setup", - "editable_grid": 0, - "fields": [ - { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fetch_if_empty": 0, - "fieldname": "antibiotic_name", - "fieldtype": "Data", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 1, - "in_standard_filter": 0, - "label": "Antibiotic Name", - "length": 0, - "no_copy": 0, - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 1, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 1 - }, - { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fetch_if_empty": 0, - "fieldname": "abbr", - "fieldtype": "Data", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "label": "Abbr", - "length": 0, - "no_copy": 0, - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 1 - } - ], - "has_web_view": 0, - "hide_heading": 0, - "hide_toolbar": 0, - "idx": 0, - "image_view": 0, - "in_create": 0, - "is_submittable": 0, - "issingle": 0, - "istable": 0, - "max_attachments": 0, - "modified": "2019-10-01 17:58:23.136498", - "modified_by": "Administrator", - "module": "Healthcare", - "name": "Antibiotic", - "name_case": "", - "owner": "Administrator", - "permissions": [ - { - "amend": 0, - "cancel": 0, - "create": 1, - "delete": 1, - "email": 1, - "export": 1, - "if_owner": 0, - "import": 0, - "permlevel": 0, - "print": 1, - "read": 1, - "report": 1, - "role": "Healthcare Administrator", - "set_user_permissions": 0, - "share": 1, - "submit": 0, - "write": 1 - }, - { - "amend": 0, - "cancel": 0, - "create": 0, - "delete": 0, - "email": 1, - "export": 1, - "if_owner": 0, - "import": 0, - "permlevel": 0, - "print": 1, - "read": 1, - "report": 1, - "role": "Laboratory User", - "set_user_permissions": 0, - "share": 1, - "submit": 0, - "write": 0 - } - ], - "quick_entry": 1, - "read_only": 0, - "read_only_onload": 0, - "restrict_to_domain": "Healthcare", - "search_fields": "antibiotic_name", - "show_name_in_global_search": 0, - "sort_field": "modified", - "sort_order": "DESC", - "title_field": "antibiotic_name", - "track_changes": 0, - "track_seen": 0, - "track_views": 0 -} \ No newline at end of file diff --git a/erpnext/healthcare/doctype/antibiotic/antibiotic.py b/erpnext/healthcare/doctype/antibiotic/antibiotic.py deleted file mode 100644 index 6a4b7648b96..00000000000 --- a/erpnext/healthcare/doctype/antibiotic/antibiotic.py +++ /dev/null @@ -1,11 +0,0 @@ -# -*- coding: utf-8 -*- -# Copyright (c) 2017, Frappe Technologies Pvt. Ltd. and contributors -# For license information, please see license.txt - -from __future__ import unicode_literals - -from frappe.model.document import Document - - -class Antibiotic(Document): - pass diff --git a/erpnext/healthcare/doctype/antibiotic/test_antibiotic.py b/erpnext/healthcare/doctype/antibiotic/test_antibiotic.py deleted file mode 100644 index b6ec79f7ff4..00000000000 --- a/erpnext/healthcare/doctype/antibiotic/test_antibiotic.py +++ /dev/null @@ -1,10 +0,0 @@ -# -*- coding: utf-8 -*- -# Copyright (c) 2017, Frappe Technologies Pvt. Ltd. and Contributors -# See license.txt -from __future__ import unicode_literals - -import unittest - - -class TestAntibiotic(unittest.TestCase): - pass diff --git a/erpnext/healthcare/doctype/appointment_type/appointment_type.js b/erpnext/healthcare/doctype/appointment_type/appointment_type.js deleted file mode 100644 index 99b7cb295a9..00000000000 --- a/erpnext/healthcare/doctype/appointment_type/appointment_type.js +++ /dev/null @@ -1,83 +0,0 @@ -// Copyright (c) 2016, ESS LLP and contributors -// For license information, please see license.txt - -frappe.ui.form.on('Appointment Type', { - refresh: function(frm) { - frm.set_query('price_list', function() { - return { - filters: {'selling': 1} - }; - }); - - frm.set_query('medical_department', 'items', function(doc) { - let item_list = doc.items.map(({medical_department}) => medical_department); - return { - filters: [ - ['Medical Department', 'name', 'not in', item_list] - ] - }; - }); - - frm.set_query('op_consulting_charge_item', 'items', function() { - return { - filters: { - is_stock_item: 0 - } - }; - }); - - frm.set_query('inpatient_visit_charge_item', 'items', function() { - return { - filters: { - is_stock_item: 0 - } - }; - }); - } -}); - -frappe.ui.form.on('Appointment Type Service Item', { - op_consulting_charge_item: function(frm, cdt, cdn) { - let d = locals[cdt][cdn]; - if (frm.doc.price_list && d.op_consulting_charge_item) { - frappe.call({ - 'method': 'frappe.client.get_value', - args: { - 'doctype': 'Item Price', - 'filters': { - 'item_code': d.op_consulting_charge_item, - 'price_list': frm.doc.price_list - }, - 'fieldname': ['price_list_rate'] - }, - callback: function(data) { - if (data.message.price_list_rate) { - frappe.model.set_value(cdt, cdn, 'op_consulting_charge', data.message.price_list_rate); - } - } - }); - } - }, - - inpatient_visit_charge_item: function(frm, cdt, cdn) { - let d = locals[cdt][cdn]; - if (frm.doc.price_list && d.inpatient_visit_charge_item) { - frappe.call({ - 'method': 'frappe.client.get_value', - args: { - 'doctype': 'Item Price', - 'filters': { - 'item_code': d.inpatient_visit_charge_item, - 'price_list': frm.doc.price_list - }, - 'fieldname': ['price_list_rate'] - }, - callback: function (data) { - if (data.message.price_list_rate) { - frappe.model.set_value(cdt, cdn, 'inpatient_visit_charge', data.message.price_list_rate); - } - } - }); - } - } -}); diff --git a/erpnext/healthcare/doctype/appointment_type/appointment_type.json b/erpnext/healthcare/doctype/appointment_type/appointment_type.json deleted file mode 100644 index 38723182878..00000000000 --- a/erpnext/healthcare/doctype/appointment_type/appointment_type.json +++ /dev/null @@ -1,114 +0,0 @@ -{ - "actions": [], - "allow_import": 1, - "allow_rename": 1, - "autoname": "field:appointment_type", - "beta": 1, - "creation": "2016-07-22 11:52:34.953019", - "doctype": "DocType", - "document_type": "Setup", - "engine": "InnoDB", - "field_order": [ - "appointment_type", - "ip", - "default_duration", - "color", - "billing_section", - "price_list", - "items" - ], - "fields": [ - { - "allow_in_quick_entry": 1, - "fieldname": "appointment_type", - "fieldtype": "Data", - "ignore_xss_filter": 1, - "in_list_view": 1, - "label": "Type", - "reqd": 1, - "translatable": 1, - "unique": 1 - }, - { - "bold": 1, - "default": "0", - "fieldname": "ip", - "fieldtype": "Check", - "label": "Is Inpatient", - "print_hide": 1, - "report_hide": 1 - }, - { - "allow_in_quick_entry": 1, - "bold": 1, - "fieldname": "default_duration", - "fieldtype": "Int", - "in_filter": 1, - "in_list_view": 1, - "label": "Default Duration (In Minutes)" - }, - { - "allow_in_quick_entry": 1, - "fieldname": "color", - "fieldtype": "Color", - "in_list_view": 1, - "label": "Color", - "no_copy": 1, - "report_hide": 1 - }, - { - "fieldname": "billing_section", - "fieldtype": "Section Break", - "label": "Billing" - }, - { - "fieldname": "price_list", - "fieldtype": "Link", - "label": "Price List", - "options": "Price List" - }, - { - "fieldname": "items", - "fieldtype": "Table", - "label": "Appointment Type Service Items", - "options": "Appointment Type Service Item" - } - ], - "links": [], - "modified": "2021-01-22 09:41:05.010524", - "modified_by": "Administrator", - "module": "Healthcare", - "name": "Appointment Type", - "owner": "Administrator", - "permissions": [ - { - "create": 1, - "delete": 1, - "email": 1, - "export": 1, - "print": 1, - "read": 1, - "report": 1, - "role": "Healthcare Administrator", - "share": 1, - "write": 1 - }, - { - "create": 1, - "delete": 1, - "email": 1, - "export": 1, - "print": 1, - "read": 1, - "report": 1, - "role": "Physician", - "share": 1, - "write": 1 - } - ], - "quick_entry": 1, - "restrict_to_domain": "Healthcare", - "search_fields": "appointment_type", - "sort_field": "modified", - "sort_order": "DESC" -} \ No newline at end of file diff --git a/erpnext/healthcare/doctype/appointment_type/appointment_type.py b/erpnext/healthcare/doctype/appointment_type/appointment_type.py deleted file mode 100644 index 94d023f2c3d..00000000000 --- a/erpnext/healthcare/doctype/appointment_type/appointment_type.py +++ /dev/null @@ -1,58 +0,0 @@ -# -*- coding: utf-8 -*- -# Copyright (c) 2015, ESS LLP and contributors -# For license information, please see license.txt - -from __future__ import unicode_literals - -import frappe -from frappe.model.document import Document - - -class AppointmentType(Document): - def validate(self): - if self.items and self.price_list: - for item in self.items: - existing_op_item_price = frappe.db.exists('Item Price', { - 'item_code': item.op_consulting_charge_item, - 'price_list': self.price_list - }) - - if not existing_op_item_price and item.op_consulting_charge_item and item.op_consulting_charge: - make_item_price(self.price_list, item.op_consulting_charge_item, item.op_consulting_charge) - - existing_ip_item_price = frappe.db.exists('Item Price', { - 'item_code': item.inpatient_visit_charge_item, - 'price_list': self.price_list - }) - - if not existing_ip_item_price and item.inpatient_visit_charge_item and item.inpatient_visit_charge: - make_item_price(self.price_list, item.inpatient_visit_charge_item, item.inpatient_visit_charge) - -@frappe.whitelist() -def get_service_item_based_on_department(appointment_type, department): - item_list = frappe.db.get_value('Appointment Type Service Item', - filters = {'medical_department': department, 'parent': appointment_type}, - fieldname = ['op_consulting_charge_item', - 'inpatient_visit_charge_item', 'op_consulting_charge', 'inpatient_visit_charge'], - as_dict = 1 - ) - - # if department wise items are not set up - # use the generic items - if not item_list: - item_list = frappe.db.get_value('Appointment Type Service Item', - filters = {'parent': appointment_type}, - fieldname = ['op_consulting_charge_item', - 'inpatient_visit_charge_item', 'op_consulting_charge', 'inpatient_visit_charge'], - as_dict = 1 - ) - - return item_list - -def make_item_price(price_list, item, item_price): - frappe.get_doc({ - 'doctype': 'Item Price', - 'price_list': price_list, - 'item_code': item, - 'price_list_rate': item_price - }).insert(ignore_permissions=True, ignore_mandatory=True) diff --git a/erpnext/healthcare/doctype/appointment_type/appointment_type_dashboard.py b/erpnext/healthcare/doctype/appointment_type/appointment_type_dashboard.py deleted file mode 100644 index b9c6edbb19c..00000000000 --- a/erpnext/healthcare/doctype/appointment_type/appointment_type_dashboard.py +++ /dev/null @@ -1,15 +0,0 @@ -from __future__ import unicode_literals - -from frappe import _ - - -def get_data(): - return { - 'fieldname': 'appointment_type', - 'transactions': [ - { - 'label': _('Patient Appointments'), - 'items': ['Patient Appointment'] - }, - ] - } diff --git a/erpnext/healthcare/doctype/appointment_type/test_appointment_type.py b/erpnext/healthcare/doctype/appointment_type/test_appointment_type.py deleted file mode 100644 index 04452e470e2..00000000000 --- a/erpnext/healthcare/doctype/appointment_type/test_appointment_type.py +++ /dev/null @@ -1,11 +0,0 @@ -# -*- coding: utf-8 -*- -# Copyright (c) 2015, ESS LLP and Contributors -# See license.txt -from __future__ import unicode_literals - -import unittest - -# test_records = frappe.get_test_records('Appointment Type') - -class TestAppointmentType(unittest.TestCase): - pass diff --git a/erpnext/healthcare/doctype/appointment_type_service_item/appointment_type_service_item.json b/erpnext/healthcare/doctype/appointment_type_service_item/appointment_type_service_item.json deleted file mode 100644 index ccae129ea0b..00000000000 --- a/erpnext/healthcare/doctype/appointment_type_service_item/appointment_type_service_item.json +++ /dev/null @@ -1,67 +0,0 @@ -{ - "actions": [], - "creation": "2021-01-22 09:34:53.373105", - "doctype": "DocType", - "editable_grid": 1, - "engine": "InnoDB", - "field_order": [ - "medical_department", - "op_consulting_charge_item", - "op_consulting_charge", - "column_break_4", - "inpatient_visit_charge_item", - "inpatient_visit_charge" - ], - "fields": [ - { - "fieldname": "medical_department", - "fieldtype": "Link", - "in_list_view": 1, - "label": "Medical Department", - "options": "Medical Department" - }, - { - "fieldname": "op_consulting_charge_item", - "fieldtype": "Link", - "in_list_view": 1, - "label": "Out Patient Consulting Charge Item", - "options": "Item" - }, - { - "fieldname": "op_consulting_charge", - "fieldtype": "Currency", - "in_list_view": 1, - "label": "Out Patient Consulting Charge" - }, - { - "fieldname": "column_break_4", - "fieldtype": "Column Break" - }, - { - "fieldname": "inpatient_visit_charge_item", - "fieldtype": "Link", - "in_list_view": 1, - "label": "Inpatient Visit Charge Item", - "options": "Item" - }, - { - "fieldname": "inpatient_visit_charge", - "fieldtype": "Currency", - "in_list_view": 1, - "label": "Inpatient Visit Charge" - } - ], - "index_web_pages_for_search": 1, - "istable": 1, - "links": [], - "modified": "2021-08-17 06:05:02.240812", - "modified_by": "Administrator", - "module": "Healthcare", - "name": "Appointment Type Service Item", - "owner": "Administrator", - "permissions": [], - "quick_entry": 1, - "sort_field": "modified", - "sort_order": "DESC", - "track_changes": 1 -} \ No newline at end of file diff --git a/erpnext/healthcare/doctype/body_part/body_part.js b/erpnext/healthcare/doctype/body_part/body_part.js deleted file mode 100644 index d2f9d09937d..00000000000 --- a/erpnext/healthcare/doctype/body_part/body_part.js +++ /dev/null @@ -1,8 +0,0 @@ -// Copyright (c) 2020, Frappe Technologies Pvt. Ltd. and contributors -// For license information, please see license.txt - -frappe.ui.form.on('Body Part', { - // refresh: function(frm) { - - // } -}); diff --git a/erpnext/healthcare/doctype/body_part/body_part.json b/erpnext/healthcare/doctype/body_part/body_part.json deleted file mode 100644 index 6e3d1d4ce3b..00000000000 --- a/erpnext/healthcare/doctype/body_part/body_part.json +++ /dev/null @@ -1,45 +0,0 @@ -{ - "actions": [], - "autoname": "field:body_part", - "creation": "2020-04-10 12:21:55.036402", - "doctype": "DocType", - "editable_grid": 1, - "engine": "InnoDB", - "field_order": [ - "body_part" - ], - "fields": [ - { - "fieldname": "body_part", - "fieldtype": "Data", - "in_list_view": 1, - "label": "Body Part", - "reqd": 1, - "unique": 1 - } - ], - "links": [], - "modified": "2020-04-10 12:26:44.087985", - "modified_by": "Administrator", - "module": "Healthcare", - "name": "Body Part", - "owner": "Administrator", - "permissions": [ - { - "create": 1, - "delete": 1, - "email": 1, - "export": 1, - "print": 1, - "read": 1, - "report": 1, - "role": "System Manager", - "share": 1, - "write": 1 - } - ], - "quick_entry": 1, - "sort_field": "modified", - "sort_order": "DESC", - "track_changes": 1 -} \ No newline at end of file diff --git a/erpnext/healthcare/doctype/body_part/body_part.py b/erpnext/healthcare/doctype/body_part/body_part.py deleted file mode 100644 index 77e8dd90a07..00000000000 --- a/erpnext/healthcare/doctype/body_part/body_part.py +++ /dev/null @@ -1,12 +0,0 @@ -# -*- coding: utf-8 -*- -# Copyright (c) 2020, Frappe Technologies Pvt. Ltd. and contributors -# For license information, please see license.txt - -from __future__ import unicode_literals - -# import frappe -from frappe.model.document import Document - - -class BodyPart(Document): - pass diff --git a/erpnext/healthcare/doctype/body_part/test_body_part.py b/erpnext/healthcare/doctype/body_part/test_body_part.py deleted file mode 100644 index a81ba179bfe..00000000000 --- a/erpnext/healthcare/doctype/body_part/test_body_part.py +++ /dev/null @@ -1,11 +0,0 @@ -# -*- coding: utf-8 -*- -# Copyright (c) 2020, Frappe Technologies Pvt. Ltd. and Contributors -# See license.txt -from __future__ import unicode_literals - -# import frappe -import unittest - - -class TestBodyPart(unittest.TestCase): - pass diff --git a/erpnext/healthcare/doctype/body_part_link/body_part_link.py b/erpnext/healthcare/doctype/body_part_link/body_part_link.py deleted file mode 100644 index 07488f01177..00000000000 --- a/erpnext/healthcare/doctype/body_part_link/body_part_link.py +++ /dev/null @@ -1,12 +0,0 @@ -# -*- coding: utf-8 -*- -# Copyright (c) 2020, Frappe Technologies Pvt. Ltd. and contributors -# For license information, please see license.txt - -from __future__ import unicode_literals - -# import frappe -from frappe.model.document import Document - - -class BodyPartLink(Document): - pass diff --git a/erpnext/healthcare/doctype/clinical_procedure/clinical_procedure.js b/erpnext/healthcare/doctype/clinical_procedure/clinical_procedure.js deleted file mode 100644 index b55d5d6f633..00000000000 --- a/erpnext/healthcare/doctype/clinical_procedure/clinical_procedure.js +++ /dev/null @@ -1,377 +0,0 @@ -// Copyright (c) 2017, ESS LLP and contributors -// For license information, please see license.txt - -frappe.ui.form.on('Clinical Procedure', { - setup: function(frm) { - frm.set_query('batch_no', 'items', function(doc, cdt, cdn) { - let item = locals[cdt][cdn]; - if (!item.item_code) { - frappe.throw(__('Please enter Item Code to get Batch Number')); - } else { - let filters = {'item_code': item.item_code}; - - if (frm.doc.status == 'In Progress') { - filters['posting_date'] = frm.doc.start_date || frappe.datetime.nowdate(); - if (frm.doc.warehouse) filters['warehouse'] = frm.doc.warehouse; - } - - return { - query : 'erpnext.controllers.queries.get_batch_no', - filters: filters - }; - } - }); - }, - - refresh: function(frm) { - frm.set_query('patient', function () { - return { - filters: {'status': ['!=', 'Disabled']} - }; - }); - - frm.set_query('appointment', function () { - return { - filters: { - 'procedure_template': ['not in', null], - 'status': ['in', 'Open, Scheduled'] - } - }; - }); - - frm.set_query('service_unit', function() { - return { - filters: { - 'is_group': false, - 'allow_appointments': true, - 'company': frm.doc.company - } - }; - }); - - frm.set_query('practitioner', function() { - return { - filters: { - 'department': frm.doc.medical_department - } - }; - }); - - if (frm.doc.consume_stock) { - frm.set_indicator_formatter('item_code', - function(doc) { return (doc.qty<=doc.actual_qty) ? 'green' : 'orange' ; }); - } - - if (frm.doc.docstatus == 1) { - if (frm.doc.status == 'In Progress') { - let btn_label = ''; - let msg = ''; - if (frm.doc.consume_stock) { - btn_label = __('Complete and Consume'); - msg = __('Complete {0} and Consume Stock?', [frm.doc.name]); - } else { - btn_label = 'Complete'; - msg = __('Complete {0}?', [frm.doc.name]); - } - - frm.add_custom_button(__(btn_label), function () { - frappe.confirm( - msg, - function() { - frappe.call({ - method: 'complete_procedure', - doc: frm.doc, - freeze: true, - callback: function(r) { - if (r.message) { - frappe.show_alert({ - message: __('Stock Entry {0} created', ['' + r.message + '']), - indicator: 'green' - }); - } - frm.reload_doc(); - } - }); - } - ); - }).addClass("btn-primary"); - - } else if (frm.doc.status == 'Pending') { - frm.add_custom_button(__('Start'), function() { - frappe.call({ - doc: frm.doc, - method: 'start_procedure', - callback: function(r) { - if (!r.exc) { - if (r.message == 'insufficient stock') { - let msg = __('Stock quantity to start the Procedure is not available in the Warehouse {0}. Do you want to record a Stock Entry?', [frm.doc.warehouse.bold()]); - frappe.confirm( - msg, - function() { - frappe.call({ - doc: frm.doc, - method: 'make_material_receipt', - freeze: true, - callback: function(r) { - if (!r.exc) { - frm.reload_doc(); - let doclist = frappe.model.sync(r.message); - frappe.set_route('Form', doclist[0].doctype, doclist[0].name); - } - } - }); - } - ); - } else { - frm.reload_doc(); - } - } - } - }); - }).addClass("btn-primary"); - } - } - }, - - onload: function(frm) { - if (frm.is_new()) { - frm.add_fetch('procedure_template', 'medical_department', 'medical_department'); - frm.set_value('start_time', null); - } - }, - - patient: function(frm) { - if (frm.doc.patient) { - frappe.call({ - 'method': 'erpnext.healthcare.doctype.patient.patient.get_patient_detail', - args: { - patient: frm.doc.patient - }, - callback: function (data) { - let age = ''; - if (data.message.dob) { - age = calculate_age(data.message.dob); - } else if (data.message.age) { - age = data.message.age; - if (data.message.age_as_on) { - age = __('{0} as on {1}', [age, data.message.age_as_on]); - } - } - frm.set_value('patient_name', data.message.patient_name); - frm.set_value('patient_age', age); - frm.set_value('patient_sex', data.message.sex); - } - }); - } else { - frm.set_value('patient_name', ''); - frm.set_value('patient_age', ''); - frm.set_value('patient_sex', ''); - } - }, - - appointment: function(frm) { - if (frm.doc.appointment) { - frappe.call({ - 'method': 'frappe.client.get', - args: { - doctype: 'Patient Appointment', - name: frm.doc.appointment - }, - callback: function(data) { - let values = { - 'patient':data.message.patient, - 'procedure_template': data.message.procedure_template, - 'medical_department': data.message.department, - 'practitioner': data.message.practitioner, - 'start_date': data.message.appointment_date, - 'start_time': data.message.appointment_time, - 'notes': data.message.notes, - 'service_unit': data.message.service_unit, - 'company': data.message.company - }; - frm.set_value(values); - } - }); - } else { - let values = { - 'patient': '', - 'patient_name': '', - 'patient_sex': '', - 'patient_age': '', - 'medical_department': '', - 'procedure_template': '', - 'start_date': '', - 'start_time': '', - 'notes': '', - 'service_unit': '', - 'inpatient_record': '' - }; - frm.set_value(values); - } - }, - - procedure_template: function(frm) { - if (frm.doc.procedure_template) { - frappe.call({ - 'method': 'frappe.client.get', - args: { - doctype: 'Clinical Procedure Template', - name: frm.doc.procedure_template - }, - callback: function (data) { - frm.set_value('medical_department', data.message.medical_department); - frm.set_value('consume_stock', data.message.consume_stock); - frm.events.set_warehouse(frm); - frm.events.set_procedure_consumables(frm); - } - }); - } - }, - - service_unit: function(frm) { - if (frm.doc.service_unit) { - frappe.call({ - method: 'frappe.client.get_value', - args:{ - fieldname: 'warehouse', - doctype: 'Healthcare Service Unit', - filters:{name: frm.doc.service_unit}, - }, - callback: function(data) { - if (data.message) { - frm.set_value('warehouse', data.message.warehouse); - } - } - }); - } - }, - - practitioner: function(frm) { - if (frm.doc.practitioner) { - frappe.call({ - 'method': 'frappe.client.get', - args: { - doctype: 'Healthcare Practitioner', - name: frm.doc.practitioner - }, - callback: function (data) { - frappe.model.set_value(frm.doctype,frm.docname, 'practitioner_name', data.message.practitioner_name); - } - }); - } else { - frappe.model.set_value(frm.doctype,frm.docname, 'practitioner_name', ''); - } - }, - - set_warehouse: function(frm) { - if (!frm.doc.warehouse) { - frappe.call({ - method: 'frappe.client.get_value', - args: { - doctype: 'Stock Settings', - fieldname: 'default_warehouse' - }, - callback: function (data) { - frm.set_value('warehouse', data.message.default_warehouse); - } - }); - } - }, - - set_procedure_consumables: function(frm) { - frappe.call({ - method: 'erpnext.healthcare.doctype.clinical_procedure.clinical_procedure.get_procedure_consumables', - args: { - procedure_template: frm.doc.procedure_template - }, - callback: function(data) { - if (data.message) { - frm.doc.items = []; - $.each(data.message, function(i, v) { - let item = frm.add_child('items'); - item.item_code = v.item_code; - item.item_name = v.item_name; - item.uom = v.uom; - item.stock_uom = v.stock_uom; - item.qty = flt(v.qty); - item.transfer_qty = v.transfer_qty; - item.conversion_factor = v.conversion_factor; - item.invoice_separately_as_consumables = v.invoice_separately_as_consumables; - item.batch_no = v.batch_no; - }); - refresh_field('items'); - } - } - }); - } - -}); - -frappe.ui.form.on('Clinical Procedure Item', { - qty: function(frm, cdt, cdn) { - let d = locals[cdt][cdn]; - frappe.model.set_value(cdt, cdn, 'transfer_qty', d.qty*d.conversion_factor); - }, - - uom: function(doc, cdt, cdn) { - let d = locals[cdt][cdn]; - if (d.uom && d.item_code) { - return frappe.call({ - method: 'erpnext.stock.doctype.stock_entry.stock_entry.get_uom_details', - args: { - item_code: d.item_code, - uom: d.uom, - qty: d.qty - }, - callback: function(r) { - if (r.message) { - frappe.model.set_value(cdt, cdn, r.message); - } - } - }); - } - }, - - item_code: function(frm, cdt, cdn) { - let d = locals[cdt][cdn]; - let args = null; - if (d.item_code) { - args = { - 'doctype' : 'Clinical Procedure', - 'item_code' : d.item_code, - 'company' : frm.doc.company, - 'warehouse': frm.doc.warehouse - }; - return frappe.call({ - method: 'erpnext.healthcare.doctype.clinical_procedure_template.clinical_procedure_template.get_item_details', - args: {args: args}, - callback: function(r) { - if (r.message) { - let d = locals[cdt][cdn]; - $.each(r.message, function(k, v) { - d[k] = v; - }); - refresh_field('items'); - } - } - }); - } - } -}); - -let calculate_age = function(birth) { - let ageMS = Date.parse(Date()) - Date.parse(birth); - let age = new Date(); - age.setTime(ageMS); - let years = age.getFullYear() - 1970; - return `${years} ${__('Years(s)')} ${age.getMonth()} ${__('Month(s)')} ${age.getDate()} ${__('Day(s)')}`; -}; - -// List Stock items -cur_frm.set_query('item_code', 'items', function() { - return { - filters: { - is_stock_item:1 - } - }; -}); diff --git a/erpnext/healthcare/doctype/clinical_procedure/clinical_procedure.json b/erpnext/healthcare/doctype/clinical_procedure/clinical_procedure.json deleted file mode 100644 index b1d62da0325..00000000000 --- a/erpnext/healthcare/doctype/clinical_procedure/clinical_procedure.json +++ /dev/null @@ -1,345 +0,0 @@ -{ - "actions": [], - "autoname": "naming_series:", - "beta": 1, - "creation": "2017-04-07 12:52:43.542429", - "doctype": "DocType", - "editable_grid": 1, - "engine": "InnoDB", - "field_order": [ - "naming_series", - "title", - "appointment", - "procedure_template", - "medical_code", - "column_break_30", - "company", - "invoiced", - "section_break_6", - "patient", - "patient_name", - "patient_sex", - "patient_age", - "inpatient_record", - "notes", - "column_break_7", - "status", - "practitioner", - "practitioner_name", - "medical_department", - "service_unit", - "start_date", - "start_time", - "sample", - "consumables_section", - "consume_stock", - "warehouse", - "items", - "section_break_24", - "invoice_separately_as_consumables", - "consumption_invoiced", - "consumable_total_amount", - "column_break_27", - "consumption_details", - "sb_refs", - "column_break_34", - "prescription", - "amended_from" - ], - "fields": [ - { - "fetch_from": "patient.inpatient_record", - "fieldname": "inpatient_record", - "fieldtype": "Link", - "label": "Inpatient Record", - "options": "Inpatient Record", - "read_only": 1 - }, - { - "fieldname": "naming_series", - "fieldtype": "Select", - "label": "Series", - "options": "HLC-CPR-.YYYY.-" - }, - { - "fieldname": "appointment", - "fieldtype": "Link", - "in_standard_filter": 1, - "label": "Appointment", - "options": "Patient Appointment", - "set_only_once": 1 - }, - { - "fieldname": "patient", - "fieldtype": "Link", - "in_standard_filter": 1, - "label": "Patient", - "options": "Patient", - "reqd": 1 - }, - { - "fieldname": "patient_age", - "fieldtype": "Data", - "label": "Age", - "read_only": 1 - }, - { - "fieldname": "patient_sex", - "fieldtype": "Link", - "label": "Gender", - "options": "Gender", - "read_only": 1, - "set_only_once": 1 - }, - { - "fieldname": "prescription", - "fieldtype": "Link", - "hidden": 1, - "label": "Procedure Prescription", - "options": "Procedure Prescription", - "read_only": 1 - }, - { - "fieldname": "medical_department", - "fieldtype": "Link", - "in_standard_filter": 1, - "label": "Medical Department", - "options": "Medical Department" - }, - { - "fieldname": "practitioner", - "fieldtype": "Link", - "in_standard_filter": 1, - "label": "Healthcare Practitioner", - "options": "Healthcare Practitioner" - }, - { - "fieldname": "column_break_7", - "fieldtype": "Column Break" - }, - { - "fieldname": "procedure_template", - "fieldtype": "Link", - "in_list_view": 1, - "label": "Procedure Template", - "options": "Clinical Procedure Template", - "reqd": 1 - }, - { - "fieldname": "service_unit", - "fieldtype": "Link", - "label": "Service Unit", - "options": "Healthcare Service Unit", - "set_only_once": 1 - }, - { - "fieldname": "warehouse", - "fieldtype": "Link", - "label": "Warehouse", - "mandatory_depends_on": "eval: doc.consume_stock == 1", - "options": "Warehouse" - }, - { - "default": "Today", - "fieldname": "start_date", - "fieldtype": "Date", - "label": "Start Date" - }, - { - "fieldname": "start_time", - "fieldtype": "Time", - "label": "Start Time" - }, - { - "fieldname": "sample", - "fieldtype": "Link", - "label": "Sample", - "options": "Sample Collection" - }, - { - "default": "0", - "fieldname": "invoiced", - "fieldtype": "Check", - "label": "Invoiced", - "no_copy": 1, - "read_only": 1 - }, - { - "fieldname": "notes", - "fieldtype": "Small Text", - "label": "Notes", - "set_only_once": 1 - }, - { - "fieldname": "company", - "fieldtype": "Link", - "label": "Company", - "options": "Company" - }, - { - "default": "0", - "fieldname": "consume_stock", - "fieldtype": "Check", - "label": "Consume Stock" - }, - { - "fieldname": "items", - "fieldtype": "Table", - "label": "Consumables", - "options": "Clinical Procedure Item" - }, - { - "default": "0", - "fieldname": "invoice_separately_as_consumables", - "fieldtype": "Check", - "hidden": 1, - "label": "Invoice Consumables Separately", - "read_only": 1 - }, - { - "depends_on": "invoice_separately_as_consumables", - "fieldname": "consumable_total_amount", - "fieldtype": "Currency", - "label": "Consumable Total Amount", - "read_only": 1 - }, - { - "depends_on": "invoice_separately_as_consumables", - "fieldname": "consumption_details", - "fieldtype": "Small Text", - "label": "Consumption Details" - }, - { - "default": "0", - "depends_on": "invoice_separately_as_consumables", - "fieldname": "consumption_invoiced", - "fieldtype": "Check", - "hidden": 1, - "label": "Consumption Invoiced", - "read_only": 1 - }, - { - "depends_on": "eval:!doc.__islocal", - "fieldname": "status", - "fieldtype": "Select", - "in_list_view": 1, - "in_standard_filter": 1, - "label": "Status", - "options": "Draft\nSubmitted\nCancelled\nIn Progress\nCompleted\nPending", - "read_only": 1 - }, - { - "fieldname": "amended_from", - "fieldtype": "Link", - "label": "Amended From", - "no_copy": 1, - "options": "Clinical Procedure", - "print_hide": 1, - "read_only": 1 - }, - { - "collapsible": 1, - "collapsible_depends_on": "consume_stock", - "fieldname": "consumables_section", - "fieldtype": "Section Break", - "label": "Consumables" - }, - { - "fieldname": "column_break_27", - "fieldtype": "Column Break" - }, - { - "fieldname": "section_break_24", - "fieldtype": "Section Break" - }, - { - "fieldname": "column_break_30", - "fieldtype": "Column Break" - }, - { - "fieldname": "section_break_6", - "fieldtype": "Section Break" - }, - { - "collapsible": 1, - "fieldname": "sb_refs", - "fieldtype": "Section Break" - }, - { - "fieldname": "patient_name", - "fieldtype": "Data", - "label": "Patient Name", - "read_only": 1 - }, - { - "fieldname": "practitioner_name", - "fieldtype": "Data", - "in_list_view": 1, - "label": "Practitioner Name", - "read_only": 1 - }, - { - "fieldname": "column_break_34", - "fieldtype": "Column Break" - }, - { - "allow_on_submit": 1, - "fieldname": "title", - "fieldtype": "Data", - "hidden": 1, - "label": "Title", - "no_copy": 1, - "print_hide": 1, - "read_only": 1 - }, - { - "fetch_from": "procedure_template.medical_code", - "fieldname": "medical_code", - "fieldtype": "Link", - "label": "Medical Code", - "options": "Medical Code", - "read_only": 1 - } - ], - "is_submittable": 1, - "links": [], - "modified": "2020-06-29 14:28:11.779815", - "modified_by": "Administrator", - "module": "Healthcare", - "name": "Clinical Procedure", - "owner": "Administrator", - "permissions": [ - { - "create": 1, - "delete": 1, - "email": 1, - "export": 1, - "print": 1, - "read": 1, - "report": 1, - "role": "Nursing User", - "share": 1, - "submit": 1, - "write": 1 - }, - { - "cancel": 1, - "create": 1, - "delete": 1, - "email": 1, - "export": 1, - "print": 1, - "read": 1, - "report": 1, - "role": "Physician", - "share": 1, - "submit": 1, - "write": 1 - } - ], - "restrict_to_domain": "Healthcare", - "sort_field": "modified", - "sort_order": "DESC", - "title_field": "title", - "track_changes": 1 -} \ No newline at end of file diff --git a/erpnext/healthcare/doctype/clinical_procedure/clinical_procedure.py b/erpnext/healthcare/doctype/clinical_procedure/clinical_procedure.py deleted file mode 100644 index df4c2ef9055..00000000000 --- a/erpnext/healthcare/doctype/clinical_procedure/clinical_procedure.py +++ /dev/null @@ -1,255 +0,0 @@ -# -*- coding: utf-8 -*- -# Copyright (c) 2017, ESS LLP and contributors -# For license information, please see license.txt - -from __future__ import unicode_literals - -import frappe -from frappe import _ -from frappe.model.document import Document -from frappe.model.mapper import get_mapped_doc -from frappe.utils import flt, nowdate, nowtime - -from erpnext.healthcare.doctype.healthcare_settings.healthcare_settings import get_account -from erpnext.healthcare.doctype.lab_test.lab_test import create_sample_doc -from erpnext.stock.get_item_details import get_item_details -from erpnext.stock.stock_ledger import get_previous_sle - - -class ClinicalProcedure(Document): - def validate(self): - self.set_status() - self.set_title() - if self.consume_stock: - self.set_actual_qty() - - if self.items: - self.invoice_separately_as_consumables = False - for item in self.items: - if item.invoice_separately_as_consumables: - self.invoice_separately_as_consumables = True - - def before_insert(self): - if self.consume_stock: - self.set_actual_qty() - - def after_insert(self): - if self.prescription: - frappe.db.set_value('Procedure Prescription', self.prescription, 'procedure_created', 1) - if self.appointment: - frappe.db.set_value('Patient Appointment', self.appointment, 'status', 'Closed') - template = frappe.get_doc('Clinical Procedure Template', self.procedure_template) - if template.sample: - patient = frappe.get_doc('Patient', self.patient) - sample_collection = create_sample_doc(template, patient, None, self.company) - frappe.db.set_value('Clinical Procedure', self.name, 'sample', sample_collection.name) - self.reload() - - def set_status(self): - if self.docstatus == 0: - self.status = 'Draft' - elif self.docstatus == 1: - if self.status not in ['In Progress', 'Completed']: - self.status = 'Pending' - elif self.docstatus == 2: - self.status = 'Cancelled' - - def set_title(self): - self.title = _('{0} - {1}').format(self.patient_name or self.patient, self.procedure_template)[:100] - - @frappe.whitelist() - def complete_procedure(self): - if self.consume_stock and self.items: - stock_entry = make_stock_entry(self) - - if self.items: - consumable_total_amount = 0 - consumption_details = False - customer = frappe.db.get_value('Patient', self.patient, 'customer') - if customer: - for item in self.items: - if item.invoice_separately_as_consumables: - price_list, price_list_currency = frappe.db.get_values('Price List', {'selling': 1}, ['name', 'currency'])[0] - args = { - 'doctype': 'Sales Invoice', - 'item_code': item.item_code, - 'company': self.company, - 'warehouse': self.warehouse, - 'customer': customer, - 'selling_price_list': price_list, - 'price_list_currency': price_list_currency, - 'plc_conversion_rate': 1.0, - 'conversion_rate': 1.0 - } - item_details = get_item_details(args) - item_price = item_details.price_list_rate * item.qty - item_consumption_details = item_details.item_name + ' ' + str(item.qty) + ' ' + item.uom + ' ' + str(item_price) - consumable_total_amount += item_price - if not consumption_details: - consumption_details = _('Clinical Procedure ({0}):').format(self.name) - consumption_details += '\n\t' + item_consumption_details - - if consumable_total_amount > 0: - frappe.db.set_value('Clinical Procedure', self.name, 'consumable_total_amount', consumable_total_amount) - frappe.db.set_value('Clinical Procedure', self.name, 'consumption_details', consumption_details) - else: - frappe.throw(_('Please set Customer in Patient {0}').format(frappe.bold(self.patient)), title=_('Customer Not Found')) - - self.db_set('status', 'Completed') - - if self.consume_stock and self.items: - return stock_entry - - @frappe.whitelist() - def start_procedure(self): - allow_start = self.set_actual_qty() - if allow_start: - self.db_set('status', 'In Progress') - return 'success' - return 'insufficient stock' - - def set_actual_qty(self): - allow_negative_stock = frappe.db.get_single_value('Stock Settings', 'allow_negative_stock') - - allow_start = True - for d in self.get('items'): - d.actual_qty = get_stock_qty(d.item_code, self.warehouse) - # validate qty - if not allow_negative_stock and d.actual_qty < d.qty: - allow_start = False - break - - return allow_start - - @frappe.whitelist() - def make_material_receipt(self, submit=False): - stock_entry = frappe.new_doc('Stock Entry') - - stock_entry.stock_entry_type = 'Material Receipt' - stock_entry.to_warehouse = self.warehouse - stock_entry.company = self.company - expense_account = get_account(None, 'expense_account', 'Healthcare Settings', self.company) - for item in self.items: - if item.qty > item.actual_qty: - se_child = stock_entry.append('items') - se_child.item_code = item.item_code - se_child.item_name = item.item_name - se_child.uom = item.uom - se_child.stock_uom = item.stock_uom - se_child.qty = flt(item.qty - item.actual_qty) - se_child.t_warehouse = self.warehouse - # in stock uom - se_child.transfer_qty = flt(item.transfer_qty) - se_child.conversion_factor = flt(item.conversion_factor) - cost_center = frappe.get_cached_value('Company', self.company, 'cost_center') - se_child.cost_center = cost_center - se_child.expense_account = expense_account - if submit: - stock_entry.submit() - return stock_entry - return stock_entry.as_dict() - - -def get_stock_qty(item_code, warehouse): - return get_previous_sle({ - 'item_code': item_code, - 'warehouse': warehouse, - 'posting_date': nowdate(), - 'posting_time': nowtime() - }).get('qty_after_transaction') or 0 - - -@frappe.whitelist() -def get_procedure_consumables(procedure_template): - return get_items('Clinical Procedure Item', procedure_template, 'Clinical Procedure Template') - - -@frappe.whitelist() -def set_stock_items(doc, stock_detail_parent, parenttype): - items = get_items('Clinical Procedure Item', stock_detail_parent, parenttype) - - for item in items: - se_child = doc.append('items') - se_child.item_code = item.item_code - se_child.item_name = item.item_name - se_child.uom = item.uom - se_child.stock_uom = item.stock_uom - se_child.qty = flt(item.qty) - # in stock uom - se_child.transfer_qty = flt(item.transfer_qty) - se_child.conversion_factor = flt(item.conversion_factor) - if item.batch_no: - se_child.batch_no = item.batch_no - if parenttype == 'Clinical Procedure Template': - se_child.invoice_separately_as_consumables = item.invoice_separately_as_consumables - - return doc - - -def get_items(table, parent, parenttype): - items = frappe.db.get_all(table, filters={ - 'parent': parent, - 'parenttype': parenttype - }, fields=['*']) - - return items - - -@frappe.whitelist() -def make_stock_entry(doc): - stock_entry = frappe.new_doc('Stock Entry') - stock_entry = set_stock_items(stock_entry, doc.name, 'Clinical Procedure') - stock_entry.stock_entry_type = 'Material Issue' - stock_entry.from_warehouse = doc.warehouse - stock_entry.company = doc.company - expense_account = get_account(None, 'expense_account', 'Healthcare Settings', doc.company) - - for item_line in stock_entry.items: - cost_center = frappe.get_cached_value('Company', doc.company, 'cost_center') - item_line.cost_center = cost_center - item_line.expense_account = expense_account - - stock_entry.save(ignore_permissions=True) - stock_entry.submit() - return stock_entry.name - - -@frappe.whitelist() -def make_procedure(source_name, target_doc=None): - def set_missing_values(source, target): - consume_stock = frappe.db.get_value('Clinical Procedure Template', source.procedure_template, 'consume_stock') - if consume_stock: - target.consume_stock = 1 - warehouse = None - if source.service_unit: - warehouse = frappe.db.get_value('Healthcare Service Unit', source.service_unit, 'warehouse') - if not warehouse: - warehouse = frappe.db.get_value('Stock Settings', None, 'default_warehouse') - if warehouse: - target.warehouse = warehouse - - set_stock_items(target, source.procedure_template, 'Clinical Procedure Template') - - doc = get_mapped_doc('Patient Appointment', source_name, { - 'Patient Appointment': { - 'doctype': 'Clinical Procedure', - 'field_map': [ - ['appointment', 'name'], - ['patient', 'patient'], - ['patient_age', 'patient_age'], - ['patient_sex', 'patient_sex'], - ['procedure_template', 'procedure_template'], - ['prescription', 'procedure_prescription'], - ['practitioner', 'practitioner'], - ['medical_department', 'department'], - ['start_date', 'appointment_date'], - ['start_time', 'appointment_time'], - ['notes', 'notes'], - ['service_unit', 'service_unit'], - ['company', 'company'], - ['invoiced', 'invoiced'] - ] - } - }, target_doc, set_missing_values) - - return doc diff --git a/erpnext/healthcare/doctype/clinical_procedure/clinical_procedure_list.js b/erpnext/healthcare/doctype/clinical_procedure/clinical_procedure_list.js deleted file mode 100644 index c8601f96772..00000000000 --- a/erpnext/healthcare/doctype/clinical_procedure/clinical_procedure_list.js +++ /dev/null @@ -1,11 +0,0 @@ -frappe.listview_settings['Clinical Procedure'] = { - get_indicator: function(doc) { - var colors = { - 'Completed': 'green', - 'In Progress': 'orange', - 'Pending': 'orange', - 'Cancelled': 'grey' - }; - return [__(doc.status), colors[doc.status], 'status,=,' + doc.status]; - } -}; diff --git a/erpnext/healthcare/doctype/clinical_procedure/test_clinical_procedure.py b/erpnext/healthcare/doctype/clinical_procedure/test_clinical_procedure.py deleted file mode 100644 index b5c3744204a..00000000000 --- a/erpnext/healthcare/doctype/clinical_procedure/test_clinical_procedure.py +++ /dev/null @@ -1,71 +0,0 @@ - # -*- coding: utf-8 -*- -# Copyright (c) 2017, ESS LLP and Contributors -# See license.txt -from __future__ import unicode_literals - -import unittest - -import frappe - -from erpnext.healthcare.doctype.patient_appointment.test_patient_appointment import ( - create_clinical_procedure_template, - create_healthcare_docs, -) - -test_dependencies = ['Item'] - -class TestClinicalProcedure(unittest.TestCase): - def test_procedure_template_item(self): - patient, practitioner = create_healthcare_docs() - procedure_template = create_clinical_procedure_template() - self.assertTrue(frappe.db.exists('Item', procedure_template.item)) - - procedure_template.disabled = 1 - procedure_template.save() - self.assertEqual(frappe.db.get_value('Item', procedure_template.item, 'disabled'), 1) - - def test_consumables(self): - patient, practitioner = create_healthcare_docs() - procedure_template = create_clinical_procedure_template() - procedure_template.allow_stock_consumption = 1 - consumable = create_consumable() - procedure_template.append('items', { - 'item_code': consumable.item_code, - 'qty': 1, - 'uom': consumable.stock_uom, - 'stock_uom': consumable.stock_uom - }) - procedure_template.save() - procedure = create_procedure(procedure_template, patient, practitioner) - result = procedure.start_procedure() - if result == 'insufficient stock': - procedure.make_material_receipt(submit=True) - result = procedure.start_procedure() - self.assertEqual(procedure.status, 'In Progress') - result = procedure.complete_procedure() - # check consumption - self.assertTrue(frappe.db.exists('Stock Entry', result)) - - -def create_consumable(): - if frappe.db.exists('Item', 'Syringe'): - return frappe.get_doc('Item', 'Syringe') - consumable = frappe.new_doc('Item') - consumable.item_code = 'Syringe' - consumable.item_group = '_Test Item Group' - consumable.stock_uom = 'Nos' - consumable.valuation_rate = 5.00 - consumable.save() - return consumable - -def create_procedure(procedure_template, patient, practitioner): - procedure = frappe.new_doc('Clinical Procedure') - procedure.procedure_template = procedure_template.name - procedure.patient = patient - procedure.practitioner = practitioner - procedure.consume_stock = procedure_template.allow_stock_consumption - procedure.items = procedure_template.items - procedure.company = "_Test Company" - procedure.warehouse = "_Test Warehouse - _TC" - procedure.submit() - return procedure diff --git a/erpnext/healthcare/doctype/clinical_procedure_item/clinical_procedure_item.json b/erpnext/healthcare/doctype/clinical_procedure_item/clinical_procedure_item.json deleted file mode 100644 index a7dde0bcd0a..00000000000 --- a/erpnext/healthcare/doctype/clinical_procedure_item/clinical_procedure_item.json +++ /dev/null @@ -1,123 +0,0 @@ -{ - "actions": [], - "beta": 1, - "creation": "2017-10-05 16:15:10.876952", - "doctype": "DocType", - "editable_grid": 1, - "engine": "InnoDB", - "field_order": [ - "item_code", - "item_name", - "qty", - "barcode", - "uom", - "invoice_separately_as_consumables", - "column_break_5", - "batch_no", - "conversion_factor", - "stock_uom", - "transfer_qty", - "actual_qty" - ], - "fields": [ - { - "bold": 1, - "columns": 3, - "fieldname": "item_code", - "fieldtype": "Link", - "ignore_user_permissions": 1, - "in_global_search": 1, - "in_list_view": 1, - "label": "Item", - "options": "Item", - "reqd": 1, - "search_index": 1 - }, - { - "fieldname": "barcode", - "fieldtype": "Data", - "label": "Barcode" - }, - { - "fieldname": "item_name", - "fieldtype": "Data", - "in_list_view": 1, - "label": "Item Name", - "read_only": 1 - }, - { - "fieldname": "qty", - "fieldtype": "Float", - "in_list_view": 1, - "label": "Quantity", - "reqd": 1 - }, - { - "fieldname": "uom", - "fieldtype": "Link", - "in_list_view": 1, - "label": "UOM", - "options": "UOM", - "reqd": 1 - }, - { - "default": "0", - "fieldname": "invoice_separately_as_consumables", - "fieldtype": "Check", - "in_list_view": 1, - "label": "Invoice Separately as Consumables" - }, - { - "fieldname": "column_break_5", - "fieldtype": "Column Break" - }, - { - "fieldname": "batch_no", - "fieldtype": "Link", - "label": "Batch", - "options": "Batch" - }, - { - "fieldname": "conversion_factor", - "fieldtype": "Float", - "label": "Conversion Factor", - "read_only": 1 - }, - { - "fieldname": "stock_uom", - "fieldtype": "Link", - "label": "Stock UOM", - "options": "UOM", - "read_only": 1, - "reqd": 1 - }, - { - "fieldname": "transfer_qty", - "fieldtype": "Float", - "label": "Transfer Qty", - "read_only": 1 - }, - { - "fieldname": "actual_qty", - "fieldtype": "Float", - "label": "Actual Qty (at source/target)", - "no_copy": 1, - "print_hide": 1, - "read_only": 1, - "search_index": 1 - } - ], - "istable": 1, - "links": [], - "modified": "2020-03-01 15:34:54.226722", - "modified_by": "Administrator", - "module": "Healthcare", - "name": "Clinical Procedure Item", - "owner": "Administrator", - "permissions": [], - "quick_entry": 1, - "restrict_to_domain": "Healthcare", - "sort_field": "modified", - "sort_order": "DESC", - "track_changes": 1 -} \ No newline at end of file diff --git a/erpnext/healthcare/doctype/clinical_procedure_item/clinical_procedure_item.py b/erpnext/healthcare/doctype/clinical_procedure_item/clinical_procedure_item.py deleted file mode 100644 index 16c5369cfe5..00000000000 --- a/erpnext/healthcare/doctype/clinical_procedure_item/clinical_procedure_item.py +++ /dev/null @@ -1,11 +0,0 @@ -# -*- coding: utf-8 -*- -# Copyright (c) 2017, earthians and contributors -# For license information, please see license.txt - -from __future__ import unicode_literals - -from frappe.model.document import Document - - -class ClinicalProcedureItem(Document): - pass diff --git a/erpnext/healthcare/doctype/clinical_procedure_template/clinical_procedure_template.js b/erpnext/healthcare/doctype/clinical_procedure_template/clinical_procedure_template.js deleted file mode 100644 index ae6b39bb181..00000000000 --- a/erpnext/healthcare/doctype/clinical_procedure_template/clinical_procedure_template.js +++ /dev/null @@ -1,190 +0,0 @@ -// Copyright (c) 2017, earthians and contributors -// For license information, please see license.txt - -frappe.ui.form.on('Clinical Procedure Template', { - template: function(frm) { - if (!frm.doc.item_code) - frm.set_value('item_code', frm.doc.template); - if (!frm.doc.description) - frm.set_value('description', frm.doc.template); - mark_change_in_item(frm); - }, - - rate: function(frm) { - mark_change_in_item(frm); - }, - - is_billable: function (frm) { - mark_change_in_item(frm); - }, - - item_group: function(frm) { - mark_change_in_item(frm); - }, - - description: function(frm) { - mark_change_in_item(frm); - }, - - medical_department: function(frm) { - mark_change_in_item(frm); - }, - - medical_code: function(frm) { - frm.set_query("medical_code", function() { - return { - filters: { - medical_code_standard: frm.doc.medical_code_standard - } - }; - }); - }, - - refresh: function(frm) { - frm.fields_dict['items'].grid.set_column_disp('barcode', false); - frm.fields_dict['items'].grid.set_column_disp('batch_no', false); - - if (!frm.doc.__islocal) { - cur_frm.add_custom_button(__('Change Item Code'), function() { - change_template_code(frm.doc); - }); - } - } -}); - -let mark_change_in_item = function(frm) { - if (!frm.doc.__islocal) { - frm.doc.change_in_item = 1; - } -}; - -let change_template_code = function(doc) { - let d = new frappe.ui.Dialog({ - title:__('Change Item Code'), - fields:[ - { - 'fieldtype': 'Data', - 'label': 'Item Code', - 'fieldname': 'item_code', - reqd: 1 - } - ], - primary_action: function() { - let values = d.get_values(); - - if (values) { - frappe.call({ - 'method': 'erpnext.healthcare.doctype.clinical_procedure_template.clinical_procedure_template.change_item_code_from_template', - 'args': {item_code: values.item_code, doc: doc}, - callback: function () { - cur_frm.reload_doc(); - frappe.show_alert({ - message: 'Item Code renamed successfully', - indicator: 'green' - }); - } - }); - } - d.hide(); - }, - primary_action_label: __('Change Item Code') - }); - d.show(); - - d.set_values({ - 'item_code': doc.item_code - }); -}; - -frappe.ui.form.on('Clinical Procedure Item', { - qty: function(frm, cdt, cdn) { - let d = locals[cdt][cdn]; - frappe.model.set_value(cdt, cdn, 'transfer_qty', d.qty * d.conversion_factor); - }, - - uom: function(doc, cdt, cdn){ - let d = locals[cdt][cdn]; - if (d.uom && d.item_code) { - return frappe.call({ - method: 'erpnext.stock.doctype.stock_entry.stock_entry.get_uom_details', - args: { - item_code: d.item_code, - uom: d.uom, - qty: d.qty - }, - callback: function(r) { - if (r.message) { - frappe.model.set_value(cdt, cdn, r.message); - } - } - }); - } - }, - - item_code: function(frm, cdt, cdn) { - let d = locals[cdt][cdn]; - if (d.item_code) { - let args = { - 'item_code' : d.item_code, - 'transfer_qty' : d.transfer_qty, - 'quantity' : d.qty - }; - return frappe.call({ - method: 'erpnext.healthcare.doctype.clinical_procedure_template.clinical_procedure_template.get_item_details', - args: {args: args}, - callback: function(r) { - if (r.message) { - let d = locals[cdt][cdn]; - $.each(r.message, function(k, v) { - d[k] = v; - }); - refresh_field('items'); - } - } - }); - } - } -}); - -// List Stock items -cur_frm.set_query('item_code', 'items', function() { - return { - filters: { - is_stock_item:1 - } - }; -}); - -frappe.tour['Clinical Procedure Template'] = [ - { - fieldname: 'template', - title: __('Template Name'), - description: __('Enter a name for the Clinical Procedure Template') - }, - { - fieldname: 'item_code', - title: __('Item Code'), - description: __('Set the Item Code which will be used for billing the Clinical Procedure.') - }, - { - fieldname: 'item_group', - title: __('Item Group'), - description: __('Select an Item Group for the Clinical Procedure Item.') - }, - { - fieldname: 'is_billable', - title: __('Clinical Procedure Rate'), - description: __('Check this if the Clinical Procedure is billable and also set the rate.') - }, - { - fieldname: 'consume_stock', - title: __('Allow Stock Consumption'), - description: __('Check this if the Clinical Procedure utilises consumables. Click ') + "here" + __(' to know more') - - }, - { - fieldname: 'medical_department', - title: __('Medical Department'), - description: __('You can also set the Medical Department for the template. After saving the document, an Item will automatically be created for billing this Clinical Procedure. You can then use this template while creating Clinical Procedures for Patients. Templates save you from filling up redundant data every single time. You can also create templates for other operations like Lab Tests, Therapy Sessions, etc.') - } -]; diff --git a/erpnext/healthcare/doctype/clinical_procedure_template/clinical_procedure_template.json b/erpnext/healthcare/doctype/clinical_procedure_template/clinical_procedure_template.json deleted file mode 100644 index 17ac7eb1f95..00000000000 --- a/erpnext/healthcare/doctype/clinical_procedure_template/clinical_procedure_template.json +++ /dev/null @@ -1,257 +0,0 @@ -{ - "actions": [], - "allow_import": 1, - "allow_rename": 1, - "autoname": "field:template", - "beta": 1, - "creation": "2017-10-05 14:59:55.438359", - "description": "Procedure Template", - "doctype": "DocType", - "document_type": "Setup", - "editable_grid": 1, - "engine": "InnoDB", - "field_order": [ - "template", - "item", - "item_code", - "item_group", - "description", - "column_break_5", - "disabled", - "is_billable", - "rate", - "medical_department", - "medical_coding_section", - "medical_code_standard", - "medical_code", - "consumables", - "consume_stock", - "items", - "sample_collection", - "sample", - "sample_uom", - "sample_qty", - "column_break_21", - "sample_details", - "change_in_item" - ], - "fields": [ - { - "fieldname": "template", - "fieldtype": "Data", - "in_global_search": 1, - "in_list_view": 1, - "label": "Template Name", - "reqd": 1, - "unique": 1 - }, - { - "fieldname": "item_code", - "fieldtype": "Data", - "label": "Item Code", - "read_only_depends_on": "eval: !doc.__islocal ", - "reqd": 1 - }, - { - "fieldname": "item_group", - "fieldtype": "Link", - "ignore_user_permissions": 1, - "in_list_view": 1, - "in_standard_filter": 1, - "label": "Item Group", - "options": "Item Group", - "reqd": 1 - }, - { - "fieldname": "medical_department", - "fieldtype": "Link", - "label": "Medical Department", - "options": "Medical Department" - }, - { - "fieldname": "column_break_5", - "fieldtype": "Column Break" - }, - { - "default": "0", - "fieldname": "is_billable", - "fieldtype": "Check", - "label": "Is Billable" - }, - { - "depends_on": "is_billable", - "fieldname": "rate", - "fieldtype": "Float", - "in_list_view": 1, - "in_standard_filter": 1, - "label": "Rate", - "mandatory_depends_on": "is_billable" - }, - { - "fieldname": "description", - "fieldtype": "Small Text", - "ignore_xss_filter": 1, - "label": "Description", - "no_copy": 1, - "reqd": 1 - }, - { - "default": "0", - "fieldname": "consume_stock", - "fieldtype": "Check", - "label": "Allow Stock Consumption", - "search_index": 1 - }, - { - "fieldname": "consumables", - "fieldtype": "Section Break", - "label": "Consumables" - }, - { - "depends_on": "eval:doc.consume_stock == 1", - "fieldname": "items", - "fieldtype": "Table", - "ignore_user_permissions": 1, - "label": "Items", - "options": "Clinical Procedure Item" - }, - { - "collapsible": 1, - "fieldname": "sample_collection", - "fieldtype": "Section Break", - "label": "Sample Collection" - }, - { - "fieldname": "sample", - "fieldtype": "Link", - "ignore_user_permissions": 1, - "label": "Sample", - "options": "Lab Test Sample" - }, - { - "fetch_from": "sample.sample_uom", - "fieldname": "sample_uom", - "fieldtype": "Data", - "label": "Sample UOM", - "read_only": 1 - }, - { - "fieldname": "sample_qty", - "fieldtype": "Float", - "label": "Quantity" - }, - { - "fieldname": "column_break_21", - "fieldtype": "Column Break" - }, - { - "fieldname": "sample_details", - "fieldtype": "Small Text", - "ignore_xss_filter": 1, - "label": "Collection Details" - }, - { - "default": "0", - "fieldname": "change_in_item", - "fieldtype": "Check", - "hidden": 1, - "label": "Change In Item", - "no_copy": 1, - "print_hide": 1, - "report_hide": 1 - }, - { - "default": "0", - "fieldname": "disabled", - "fieldtype": "Check", - "label": "Disabled" - }, - { - "fieldname": "item", - "fieldtype": "Link", - "in_list_view": 1, - "in_standard_filter": 1, - "label": "Item", - "no_copy": 1, - "options": "Item", - "read_only": 1 - }, - { - "collapsible": 1, - "fieldname": "medical_coding_section", - "fieldtype": "Section Break", - "label": "Medical Coding" - }, - { - "fieldname": "medical_code_standard", - "fieldtype": "Link", - "label": "Medical Code Standard", - "options": "Medical Code Standard" - }, - { - "depends_on": "medical_code_standard", - "fieldname": "medical_code", - "fieldtype": "Link", - "label": "Medical Code", - "options": "Medical Code" - } - ], - "links": [], - "modified": "2020-06-29 14:12:27.158130", - "modified_by": "Administrator", - "module": "Healthcare", - "name": "Clinical Procedure Template", - "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": "Healthcare Administrator", - "share": 1, - "write": 1 - }, - { - "email": 1, - "export": 1, - "print": 1, - "read": 1, - "report": 1, - "role": "Nursing User", - "share": 1 - }, - { - "email": 1, - "export": 1, - "print": 1, - "read": 1, - "report": 1, - "role": "Physician", - "share": 1, - "write": 1 - } - ], - "restrict_to_domain": "Healthcare", - "search_fields": "template", - "sort_field": "modified", - "sort_order": "DESC", - "title_field": "template", - "track_changes": 1, - "track_seen": 1 -} \ No newline at end of file diff --git a/erpnext/healthcare/doctype/clinical_procedure_template/clinical_procedure_template.py b/erpnext/healthcare/doctype/clinical_procedure_template/clinical_procedure_template.py deleted file mode 100644 index 16e0969ae40..00000000000 --- a/erpnext/healthcare/doctype/clinical_procedure_template/clinical_procedure_template.py +++ /dev/null @@ -1,124 +0,0 @@ -# -*- coding: utf-8 -*- -# Copyright (c) 2017, earthians and contributors -# For license information, please see license.txt - -from __future__ import unicode_literals - -import json - -import frappe -from frappe import _ -from frappe.model.document import Document -from frappe.model.rename_doc import rename_doc - - -class ClinicalProcedureTemplate(Document): - def validate(self): - self.enable_disable_item() - - def after_insert(self): - create_item_from_template(self) - - def on_update(self): - if self.change_in_item: - self.update_item_and_item_price() - - def enable_disable_item(self): - if self.is_billable: - if self.disabled: - frappe.db.set_value('Item', self.item, 'disabled', 1) - else: - frappe.db.set_value('Item', self.item, 'disabled', 0) - - def update_item_and_item_price(self): - if self.is_billable and self.item: - item_doc = frappe.get_doc('Item', {'item_code': self.item}) - item_doc.item_name = self.template - item_doc.item_group = self.item_group - item_doc.description = self.description - item_doc.disabled = 0 - item_doc.save(ignore_permissions=True) - - if self.rate: - item_price = frappe.get_doc('Item Price', {'item_code': self.item}) - item_price.item_name = self.template - item_price.price_list_rate = self.rate - item_price.save() - - elif not self.is_billable and self.item: - frappe.db.set_value('Item', self.item, 'disabled', 1) - - self.db_set('change_in_item', 0) - - -@frappe.whitelist() -def get_item_details(args=None): - if not isinstance(args, dict): - args = json.loads(args) - - item = frappe.db.get_all('Item', - filters={ - 'disabled': 0, - 'name': args.get('item_code') - }, - fields=['stock_uom', 'item_name'] - ) - - if not item: - frappe.throw(_('Item {0} is not active').format(args.get('item_code'))) - - item = item[0] - ret = { - 'uom': item.stock_uom, - 'stock_uom': item.stock_uom, - 'item_name': item.item_name, - 'qty': 1, - 'transfer_qty': 0, - 'conversion_factor': 1 - } - return ret - -def create_item_from_template(doc): - disabled = doc.disabled - if doc.is_billable and not doc.disabled: - disabled = 0 - - uom = frappe.db.exists('UOM', 'Unit') or frappe.db.get_single_value('Stock Settings', 'stock_uom') - item = frappe.get_doc({ - 'doctype': 'Item', - 'item_code': doc.template, - 'item_name':doc.template, - 'item_group': doc.item_group, - 'description':doc.description, - 'is_sales_item': 1, - 'is_service_item': 1, - 'is_purchase_item': 0, - 'is_stock_item': 0, - 'show_in_website': 0, - 'is_pro_applicable': 0, - 'disabled': disabled, - 'stock_uom': uom - }).insert(ignore_permissions=True, ignore_mandatory=True) - - make_item_price(item.name, doc.rate) - doc.db_set('item', item.name) - -def make_item_price(item, item_price): - price_list_name = frappe.db.get_value('Price List', {'selling': 1}) - frappe.get_doc({ - 'doctype': 'Item Price', - 'price_list': price_list_name, - 'item_code': item, - 'price_list_rate': item_price - }).insert(ignore_permissions=True, ignore_mandatory=True) - -@frappe.whitelist() -def change_item_code_from_template(item_code, doc): - doc = frappe._dict(json.loads(doc)) - - if frappe.db.exists('Item', {'item_code': item_code}): - frappe.throw(_('Item with Item Code {0} already exists').format(item_code)) - else: - rename_doc('Item', doc.item_code, item_code, ignore_permissions=True) - frappe.db.set_value('Clinical Procedure Template', doc.name, 'item_code', item_code) - return diff --git a/erpnext/healthcare/doctype/clinical_procedure_template/clinical_procedure_template_dashboard.py b/erpnext/healthcare/doctype/clinical_procedure_template/clinical_procedure_template_dashboard.py deleted file mode 100644 index a69899d3ead..00000000000 --- a/erpnext/healthcare/doctype/clinical_procedure_template/clinical_procedure_template_dashboard.py +++ /dev/null @@ -1,15 +0,0 @@ -from __future__ import unicode_literals - -from frappe import _ - - -def get_data(): - return { - 'fieldname': 'procedure_template', - 'transactions': [ - { - 'label': _('Consultations'), - 'items': ['Clinical Procedure'] - } - ] - } diff --git a/erpnext/healthcare/doctype/clinical_procedure_template/test_clinical_procedure_template.py b/erpnext/healthcare/doctype/clinical_procedure_template/test_clinical_procedure_template.py deleted file mode 100644 index f754c76341f..00000000000 --- a/erpnext/healthcare/doctype/clinical_procedure_template/test_clinical_procedure_template.py +++ /dev/null @@ -1,10 +0,0 @@ -# -*- coding: utf-8 -*- -# Copyright (c) 2017, earthians and Contributors -# See license.txt -from __future__ import unicode_literals - -import unittest - - -class TestClinicalProcedureTemplate(unittest.TestCase): - pass diff --git a/erpnext/healthcare/doctype/codification_table/codification_table.json b/erpnext/healthcare/doctype/codification_table/codification_table.json deleted file mode 100644 index 9a917b4ffff..00000000000 --- a/erpnext/healthcare/doctype/codification_table/codification_table.json +++ /dev/null @@ -1,56 +0,0 @@ -{ - "actions": [], - "allow_copy": 1, - "beta": 1, - "creation": "2017-06-22 13:09:23.159579", - "doctype": "DocType", - "editable_grid": 1, - "engine": "InnoDB", - "field_order": [ - "medical_code", - "code", - "description" - ], - "fields": [ - { - "fieldname": "medical_code", - "fieldtype": "Link", - "ignore_user_permissions": 1, - "in_list_view": 1, - "label": "Medical Code", - "options": "Medical Code", - "reqd": 1 - }, - { - "fetch_from": "medical_code.code", - "fieldname": "code", - "fieldtype": "Data", - "ignore_xss_filter": 1, - "in_list_view": 1, - "label": "Code", - "read_only": 1 - }, - { - "fetch_from": "medical_code.description", - "fieldname": "description", - "fieldtype": "Small Text", - "ignore_xss_filter": 1, - "in_list_view": 1, - "label": "Description", - "read_only": 1 - } - ], - "istable": 1, - "links": [], - "modified": "2020-02-26 13:17:49.016293", - "modified_by": "Administrator", - "module": "Healthcare", - "name": "Codification Table", - "owner": "Administrator", - "permissions": [], - "quick_entry": 1, - "restrict_to_domain": "Healthcare", - "sort_field": "modified", - "sort_order": "DESC", - "track_changes": 1 -} \ No newline at end of file diff --git a/erpnext/healthcare/doctype/codification_table/codification_table.py b/erpnext/healthcare/doctype/codification_table/codification_table.py deleted file mode 100644 index 232d92ca9df..00000000000 --- a/erpnext/healthcare/doctype/codification_table/codification_table.py +++ /dev/null @@ -1,11 +0,0 @@ -# -*- coding: utf-8 -*- -# Copyright (c) 2017, Frappe Technologies Pvt. Ltd. and contributors -# For license information, please see license.txt - -from __future__ import unicode_literals - -from frappe.model.document import Document - - -class CodificationTable(Document): - pass diff --git a/erpnext/healthcare/doctype/complaint/complaint.js b/erpnext/healthcare/doctype/complaint/complaint.js deleted file mode 100644 index 5a2d219fe3b..00000000000 --- a/erpnext/healthcare/doctype/complaint/complaint.js +++ /dev/null @@ -1,5 +0,0 @@ -// Copyright (c) 2017, Frappe Technologies Pvt. Ltd. and contributors -// For license information, please see license.txt - -frappe.ui.form.on('Complaint', { -}); diff --git a/erpnext/healthcare/doctype/complaint/complaint.json b/erpnext/healthcare/doctype/complaint/complaint.json deleted file mode 100644 index f600838b654..00000000000 --- a/erpnext/healthcare/doctype/complaint/complaint.json +++ /dev/null @@ -1,116 +0,0 @@ -{ - "allow_copy": 1, - "allow_guest_to_view": 0, - "allow_import": 1, - "allow_rename": 1, - "autoname": "field:complaints", - "beta": 1, - "creation": "2017-02-15 12:25:28.045267", - "custom": 0, - "docstatus": 0, - "doctype": "DocType", - "document_type": "", - "editable_grid": 1, - "engine": "InnoDB", - "fields": [ - { - "allow_bulk_edit": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "complaints", - "fieldtype": "Data", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 1, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 1, - "in_standard_filter": 0, - "label": "Complaints", - "length": 0, - "no_copy": 0, - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 1, - "search_index": 0, - "set_only_once": 0, - "unique": 0 - } - ], - "has_web_view": 0, - "hide_heading": 0, - "hide_toolbar": 0, - "idx": 0, - "image_view": 0, - "in_create": 0, - "is_submittable": 0, - "issingle": 0, - "istable": 0, - "max_attachments": 0, - "modified": "2017-10-05 11:18:42.017864", - "modified_by": "Administrator", - "module": "Healthcare", - "name": "Complaint", - "name_case": "", - "owner": "Administrator", - "permissions": [ - { - "amend": 0, - "apply_user_permissions": 0, - "cancel": 0, - "create": 1, - "delete": 1, - "email": 1, - "export": 1, - "if_owner": 0, - "import": 0, - "permlevel": 0, - "print": 1, - "read": 1, - "report": 1, - "role": "Healthcare Administrator", - "set_user_permissions": 0, - "share": 1, - "submit": 0, - "write": 1 - }, - { - "amend": 0, - "apply_user_permissions": 0, - "cancel": 0, - "create": 1, - "delete": 1, - "email": 1, - "export": 1, - "if_owner": 0, - "import": 0, - "permlevel": 0, - "print": 1, - "read": 1, - "report": 1, - "role": "Physician", - "set_user_permissions": 0, - "share": 1, - "submit": 0, - "write": 1 - } - ], - "quick_entry": 1, - "read_only": 0, - "read_only_onload": 0, - "restrict_to_domain": "Healthcare", - "search_fields": "complaints", - "show_name_in_global_search": 0, - "sort_field": "modified", - "sort_order": "DESC", - "title_field": "complaints", - "track_changes": 0, - "track_seen": 0 -} \ No newline at end of file diff --git a/erpnext/healthcare/doctype/complaint/complaint.py b/erpnext/healthcare/doctype/complaint/complaint.py deleted file mode 100644 index 20e00f6b029..00000000000 --- a/erpnext/healthcare/doctype/complaint/complaint.py +++ /dev/null @@ -1,11 +0,0 @@ -# -*- coding: utf-8 -*- -# Copyright (c) 2017, Frappe Technologies Pvt. Ltd. and contributors -# For license information, please see license.txt - -from __future__ import unicode_literals - -from frappe.model.document import Document - - -class Complaint(Document): - pass diff --git a/erpnext/healthcare/doctype/complaint/test_complaint.py b/erpnext/healthcare/doctype/complaint/test_complaint.py deleted file mode 100644 index d3e10692b03..00000000000 --- a/erpnext/healthcare/doctype/complaint/test_complaint.py +++ /dev/null @@ -1,10 +0,0 @@ -# -*- coding: utf-8 -*- -# Copyright (c) 2017, Frappe Technologies Pvt. Ltd. and Contributors -# See license.txt -from __future__ import unicode_literals - -import unittest - - -class TestComplaint(unittest.TestCase): - pass diff --git a/erpnext/healthcare/doctype/descriptive_test_result/descriptive_test_result.json b/erpnext/healthcare/doctype/descriptive_test_result/descriptive_test_result.json deleted file mode 100644 index fcd3828aa53..00000000000 --- a/erpnext/healthcare/doctype/descriptive_test_result/descriptive_test_result.json +++ /dev/null @@ -1,74 +0,0 @@ -{ - "actions": [], - "allow_copy": 1, - "beta": 1, - "creation": "2016-02-22 15:12:36.202380", - "doctype": "DocType", - "document_type": "Document", - "editable_grid": 1, - "engine": "InnoDB", - "field_order": [ - "lab_test_particulars", - "result_value", - "allow_blank", - "template", - "require_result_value" - ], - "fields": [ - { - "fieldname": "lab_test_particulars", - "fieldtype": "Data", - "ignore_xss_filter": 1, - "in_list_view": 1, - "label": "Particulars", - "read_only": 1 - }, - { - "depends_on": "eval:doc.require_result_value == 1", - "fieldname": "result_value", - "fieldtype": "Small Text", - "ignore_xss_filter": 1, - "in_list_view": 1, - "label": "Value" - }, - { - "fieldname": "template", - "fieldtype": "Link", - "hidden": 1, - "label": "Template", - "options": "Lab Test Template", - "print_hide": 1, - "report_hide": 1 - }, - { - "default": "0", - "fieldname": "require_result_value", - "fieldtype": "Check", - "hidden": 1, - "label": "Require Result Value", - "print_hide": 1, - "read_only": 1, - "report_hide": 1 - }, - { - "default": "1", - "fieldname": "allow_blank", - "fieldtype": "Check", - "label": "Allow Blank", - "print_hide": 1, - "read_only": 1, - "report_hide": 1 - } - ], - "istable": 1, - "links": [], - "modified": "2020-07-23 12:33:47.693065", - "modified_by": "Administrator", - "module": "Healthcare", - "name": "Descriptive Test Result", - "owner": "Administrator", - "permissions": [], - "restrict_to_domain": "Healthcare", - "sort_field": "modified", - "sort_order": "DESC" -} \ No newline at end of file diff --git a/erpnext/healthcare/doctype/descriptive_test_result/descriptive_test_result.py b/erpnext/healthcare/doctype/descriptive_test_result/descriptive_test_result.py deleted file mode 100644 index c08604694ab..00000000000 --- a/erpnext/healthcare/doctype/descriptive_test_result/descriptive_test_result.py +++ /dev/null @@ -1,11 +0,0 @@ -# -*- coding: utf-8 -*- -# Copyright (c) 2015, ESS and contributors -# For license information, please see license.txt - -from __future__ import unicode_literals - -from frappe.model.document import Document - - -class DescriptiveTestResult(Document): - pass diff --git a/erpnext/healthcare/doctype/descriptive_test_template/descriptive_test_template.json b/erpnext/healthcare/doctype/descriptive_test_template/descriptive_test_template.json deleted file mode 100644 index 9ee8f4fc686..00000000000 --- a/erpnext/healthcare/doctype/descriptive_test_template/descriptive_test_template.json +++ /dev/null @@ -1,41 +0,0 @@ -{ - "actions": [], - "allow_copy": 1, - "beta": 1, - "creation": "2016-02-22 16:12:12.394200", - "doctype": "DocType", - "document_type": "Setup", - "editable_grid": 1, - "engine": "InnoDB", - "field_order": [ - "particulars", - "allow_blank" - ], - "fields": [ - { - "fieldname": "particulars", - "fieldtype": "Data", - "ignore_xss_filter": 1, - "in_list_view": 1, - "label": "Result Component" - }, - { - "default": "0", - "fieldname": "allow_blank", - "fieldtype": "Check", - "in_list_view": 1, - "label": "Allow Blank" - } - ], - "istable": 1, - "links": [], - "modified": "2020-06-24 14:03:51.728863", - "modified_by": "Administrator", - "module": "Healthcare", - "name": "Descriptive Test Template", - "owner": "Administrator", - "permissions": [], - "restrict_to_domain": "Healthcare", - "sort_field": "modified", - "sort_order": "DESC" -} \ No newline at end of file diff --git a/erpnext/healthcare/doctype/descriptive_test_template/descriptive_test_template.py b/erpnext/healthcare/doctype/descriptive_test_template/descriptive_test_template.py deleted file mode 100644 index 84184fbcca5..00000000000 --- a/erpnext/healthcare/doctype/descriptive_test_template/descriptive_test_template.py +++ /dev/null @@ -1,11 +0,0 @@ -# -*- coding: utf-8 -*- -# Copyright (c) 2015, ESS and contributors -# For license information, please see license.txt - -from __future__ import unicode_literals - -from frappe.model.document import Document - - -class DescriptiveTestTemplate(Document): - pass diff --git a/erpnext/healthcare/doctype/diagnosis/diagnosis.js b/erpnext/healthcare/doctype/diagnosis/diagnosis.js deleted file mode 100644 index fb2557facea..00000000000 --- a/erpnext/healthcare/doctype/diagnosis/diagnosis.js +++ /dev/null @@ -1,5 +0,0 @@ -// Copyright (c) 2016, ESS LLP and contributors -// For license information, please see license.txt - -frappe.ui.form.on('Diagnosis', { -}); diff --git a/erpnext/healthcare/doctype/diagnosis/diagnosis.json b/erpnext/healthcare/doctype/diagnosis/diagnosis.json deleted file mode 100644 index 936c2c50a99..00000000000 --- a/erpnext/healthcare/doctype/diagnosis/diagnosis.json +++ /dev/null @@ -1,116 +0,0 @@ -{ - "allow_copy": 1, - "allow_guest_to_view": 0, - "allow_import": 1, - "allow_rename": 1, - "autoname": "field:diagnosis", - "beta": 1, - "creation": "2017-02-15 12:23:59.341108", - "custom": 0, - "docstatus": 0, - "doctype": "DocType", - "document_type": "", - "editable_grid": 1, - "engine": "InnoDB", - "fields": [ - { - "allow_bulk_edit": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "diagnosis", - "fieldtype": "Data", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 1, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 1, - "in_standard_filter": 0, - "label": "Diagnosis", - "length": 0, - "no_copy": 0, - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 1, - "search_index": 0, - "set_only_once": 0, - "unique": 0 - } - ], - "has_web_view": 0, - "hide_heading": 0, - "hide_toolbar": 0, - "idx": 0, - "image_view": 0, - "in_create": 0, - "is_submittable": 0, - "issingle": 0, - "istable": 0, - "max_attachments": 0, - "modified": "2017-10-05 11:25:46.107435", - "modified_by": "Administrator", - "module": "Healthcare", - "name": "Diagnosis", - "name_case": "", - "owner": "Administrator", - "permissions": [ - { - "amend": 0, - "apply_user_permissions": 0, - "cancel": 0, - "create": 1, - "delete": 1, - "email": 1, - "export": 1, - "if_owner": 0, - "import": 0, - "permlevel": 0, - "print": 1, - "read": 1, - "report": 1, - "role": "Healthcare Administrator", - "set_user_permissions": 0, - "share": 1, - "submit": 0, - "write": 1 - }, - { - "amend": 0, - "apply_user_permissions": 0, - "cancel": 0, - "create": 1, - "delete": 1, - "email": 1, - "export": 1, - "if_owner": 0, - "import": 0, - "permlevel": 0, - "print": 1, - "read": 1, - "report": 1, - "role": "Physician", - "set_user_permissions": 0, - "share": 1, - "submit": 0, - "write": 1 - } - ], - "quick_entry": 1, - "read_only": 0, - "read_only_onload": 0, - "restrict_to_domain": "Healthcare", - "search_fields": "diagnosis", - "show_name_in_global_search": 0, - "sort_field": "modified", - "sort_order": "DESC", - "title_field": "diagnosis", - "track_changes": 1, - "track_seen": 0 -} \ No newline at end of file diff --git a/erpnext/healthcare/doctype/diagnosis/diagnosis.py b/erpnext/healthcare/doctype/diagnosis/diagnosis.py deleted file mode 100644 index 05add1b5300..00000000000 --- a/erpnext/healthcare/doctype/diagnosis/diagnosis.py +++ /dev/null @@ -1,11 +0,0 @@ -# -*- coding: utf-8 -*- -# Copyright (c) 2015, ESS LLP and contributors -# For license information, please see license.txt - -from __future__ import unicode_literals - -from frappe.model.document import Document - - -class Diagnosis(Document): - pass diff --git a/erpnext/healthcare/doctype/diagnosis/test_diagnosis.py b/erpnext/healthcare/doctype/diagnosis/test_diagnosis.py deleted file mode 100644 index c79164db37a..00000000000 --- a/erpnext/healthcare/doctype/diagnosis/test_diagnosis.py +++ /dev/null @@ -1,11 +0,0 @@ -# -*- coding: utf-8 -*- -# Copyright (c) 2015, ESS LLP and Contributors -# See license.txt -from __future__ import unicode_literals - -import unittest - -# test_records = frappe.get_test_records('Diagnosis') - -class TestDiagnosis(unittest.TestCase): - pass diff --git a/erpnext/healthcare/doctype/dosage_form/dosage_form.js b/erpnext/healthcare/doctype/dosage_form/dosage_form.js deleted file mode 100644 index 60e96969f61..00000000000 --- a/erpnext/healthcare/doctype/dosage_form/dosage_form.js +++ /dev/null @@ -1,5 +0,0 @@ -// Copyright (c) 2017, ESS LLP and contributors -// For license information, please see license.txt - -frappe.ui.form.on('Dosage Form', { -}); diff --git a/erpnext/healthcare/doctype/dosage_form/dosage_form.json b/erpnext/healthcare/doctype/dosage_form/dosage_form.json deleted file mode 100644 index 350aaedcba9..00000000000 --- a/erpnext/healthcare/doctype/dosage_form/dosage_form.json +++ /dev/null @@ -1,114 +0,0 @@ -{ - "allow_copy": 1, - "allow_guest_to_view": 0, - "allow_import": 1, - "allow_rename": 1, - "autoname": "field:dosage_form", - "beta": 1, - "creation": "2017-04-08 12:04:33.987972", - "custom": 0, - "docstatus": 0, - "doctype": "DocType", - "document_type": "", - "editable_grid": 1, - "engine": "InnoDB", - "fields": [ - { - "allow_bulk_edit": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "dosage_form", - "fieldtype": "Data", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 1, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 1, - "in_standard_filter": 0, - "label": "Dosage Form", - "length": 0, - "no_copy": 0, - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 1, - "search_index": 0, - "set_only_once": 0, - "unique": 0 - } - ], - "has_web_view": 0, - "hide_heading": 0, - "hide_toolbar": 0, - "idx": 0, - "image_view": 0, - "in_create": 0, - "is_submittable": 0, - "issingle": 0, - "istable": 0, - "max_attachments": 0, - "modified": "2017-10-05 11:24:57.888091", - "modified_by": "Administrator", - "module": "Healthcare", - "name": "Dosage Form", - "name_case": "", - "owner": "Administrator", - "permissions": [ - { - "amend": 0, - "apply_user_permissions": 0, - "cancel": 0, - "create": 1, - "delete": 1, - "email": 1, - "export": 1, - "if_owner": 0, - "import": 0, - "permlevel": 0, - "print": 1, - "read": 1, - "report": 1, - "role": "Physician", - "set_user_permissions": 0, - "share": 1, - "submit": 0, - "write": 1 - }, - { - "amend": 0, - "apply_user_permissions": 0, - "cancel": 0, - "create": 1, - "delete": 1, - "email": 1, - "export": 1, - "if_owner": 0, - "import": 0, - "permlevel": 0, - "print": 1, - "read": 1, - "report": 1, - "role": "Healthcare Administrator", - "set_user_permissions": 0, - "share": 1, - "submit": 0, - "write": 1 - } - ], - "quick_entry": 1, - "read_only": 0, - "read_only_onload": 0, - "restrict_to_domain": "Healthcare", - "show_name_in_global_search": 0, - "sort_field": "modified", - "sort_order": "DESC", - "track_changes": 1, - "track_seen": 0 -} \ No newline at end of file diff --git a/erpnext/healthcare/doctype/dosage_form/dosage_form.py b/erpnext/healthcare/doctype/dosage_form/dosage_form.py deleted file mode 100644 index 6b2d88b61b8..00000000000 --- a/erpnext/healthcare/doctype/dosage_form/dosage_form.py +++ /dev/null @@ -1,11 +0,0 @@ -# -*- coding: utf-8 -*- -# Copyright (c) 2017, ESS LLP and contributors -# For license information, please see license.txt - -from __future__ import unicode_literals - -from frappe.model.document import Document - - -class DosageForm(Document): - pass diff --git a/erpnext/healthcare/doctype/dosage_form/test_dosage_form.py b/erpnext/healthcare/doctype/dosage_form/test_dosage_form.py deleted file mode 100644 index 0161b82ba3b..00000000000 --- a/erpnext/healthcare/doctype/dosage_form/test_dosage_form.py +++ /dev/null @@ -1,10 +0,0 @@ -# -*- coding: utf-8 -*- -# Copyright (c) 2017, ESS LLP and Contributors -# See license.txt -from __future__ import unicode_literals - -import unittest - - -class TestDosageForm(unittest.TestCase): - pass diff --git a/erpnext/healthcare/doctype/dosage_strength/dosage_strength.json b/erpnext/healthcare/doctype/dosage_strength/dosage_strength.json deleted file mode 100644 index da4f1a79646..00000000000 --- a/erpnext/healthcare/doctype/dosage_strength/dosage_strength.json +++ /dev/null @@ -1,102 +0,0 @@ -{ - "allow_copy": 1, - "allow_guest_to_view": 0, - "allow_import": 0, - "allow_rename": 0, - "beta": 1, - "creation": "2017-02-14 15:40:14.385707", - "custom": 0, - "docstatus": 0, - "doctype": "DocType", - "document_type": "", - "editable_grid": 1, - "engine": "InnoDB", - "fields": [ - { - "allow_bulk_edit": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "strength", - "fieldtype": "Float", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 1, - "in_standard_filter": 0, - "label": "Strength", - "length": 0, - "no_copy": 0, - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 1, - "search_index": 0, - "set_only_once": 0, - "unique": 0 - }, - { - "allow_bulk_edit": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "strength_time", - "fieldtype": "Time", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 1, - "in_standard_filter": 0, - "label": "Time", - "length": 0, - "no_copy": 0, - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "unique": 0 - } - ], - "has_web_view": 0, - "hide_heading": 0, - "hide_toolbar": 0, - "idx": 0, - "image_view": 0, - "in_create": 0, - "is_submittable": 0, - "issingle": 0, - "istable": 1, - "max_attachments": 0, - "modified": "2017-08-31 14:11:59.874645", - "modified_by": "Administrator", - "module": "Healthcare", - "name": "Dosage Strength", - "name_case": "", - "owner": "Administrator", - "permissions": [], - "quick_entry": 1, - "read_only": 0, - "read_only_onload": 0, - "restrict_to_domain": "Healthcare", - "show_name_in_global_search": 0, - "sort_field": "modified", - "sort_order": "DESC", - "track_changes": 0, - "track_seen": 0 -} \ No newline at end of file diff --git a/erpnext/healthcare/doctype/dosage_strength/dosage_strength.py b/erpnext/healthcare/doctype/dosage_strength/dosage_strength.py deleted file mode 100644 index 9e74743a7c6..00000000000 --- a/erpnext/healthcare/doctype/dosage_strength/dosage_strength.py +++ /dev/null @@ -1,11 +0,0 @@ -# -*- coding: utf-8 -*- -# Copyright (c) 2015, ESS LLP and contributors -# For license information, please see license.txt - -from __future__ import unicode_literals - -from frappe.model.document import Document - - -class DosageStrength(Document): - pass diff --git a/erpnext/healthcare/doctype/drug_prescription/drug_prescription.json b/erpnext/healthcare/doctype/drug_prescription/drug_prescription.json deleted file mode 100644 index a65c56694e7..00000000000 --- a/erpnext/healthcare/doctype/drug_prescription/drug_prescription.json +++ /dev/null @@ -1,122 +0,0 @@ -{ - "actions": [], - "allow_copy": 1, - "beta": 1, - "creation": "2016-09-16 16:41:45.533374", - "doctype": "DocType", - "document_type": "Document", - "editable_grid": 1, - "engine": "InnoDB", - "field_order": [ - "drug_code", - "drug_name", - "dosage", - "period", - "dosage_form", - "column_break_7", - "comment", - "usage_interval", - "interval", - "interval_uom", - "update_schedule" - ], - "fields": [ - { - "fieldname": "drug_code", - "fieldtype": "Link", - "ignore_user_permissions": 1, - "in_list_view": 1, - "label": "Drug", - "options": "Item", - "reqd": 1 - }, - { - "fetch_from": "drug_code.item_name", - "fieldname": "drug_name", - "fieldtype": "Data", - "in_list_view": 1, - "label": "Drug Name / Description" - }, - { - "fieldname": "dosage", - "fieldtype": "Link", - "ignore_user_permissions": 1, - "in_list_view": 1, - "label": "Dosage", - "options": "Prescription Dosage", - "reqd": 1 - }, - { - "fieldname": "period", - "fieldtype": "Link", - "ignore_user_permissions": 1, - "in_list_view": 1, - "label": "Period", - "options": "Prescription Duration", - "reqd": 1 - }, - { - "allow_in_quick_entry": 1, - "fieldname": "dosage_form", - "fieldtype": "Link", - "ignore_user_permissions": 1, - "label": "Dosage Form", - "options": "Dosage Form", - "reqd": 1 - }, - { - "fieldname": "column_break_7", - "fieldtype": "Column Break" - }, - { - "fieldname": "comment", - "fieldtype": "Small Text", - "ignore_xss_filter": 1, - "in_list_view": 1, - "label": "Comment" - }, - { - "depends_on": "usage_interval", - "fieldname": "interval", - "fieldtype": "Int", - "in_list_view": 1, - "label": "Interval" - }, - { - "default": "1", - "depends_on": "usage_interval", - "fieldname": "update_schedule", - "fieldtype": "Check", - "hidden": 1, - "label": "Update Schedule", - "print_hide": 1, - "report_hide": 1 - }, - { - "depends_on": "use_interval", - "fieldname": "interval_uom", - "fieldtype": "Select", - "in_list_view": 1, - "label": "Interval UOM", - "options": "\nHour\nDay" - }, - { - "default": "0", - "fieldname": "usage_interval", - "fieldtype": "Check", - "hidden": 1, - "label": "Dosage by Time Interval" - } - ], - "istable": 1, - "links": [], - "modified": "2021-06-11 11:53:06.343704", - "modified_by": "Administrator", - "module": "Healthcare", - "name": "Drug Prescription", - "owner": "Administrator", - "permissions": [], - "restrict_to_domain": "Healthcare", - "sort_field": "modified", - "sort_order": "DESC" -} \ No newline at end of file diff --git a/erpnext/healthcare/doctype/drug_prescription/drug_prescription.py b/erpnext/healthcare/doctype/drug_prescription/drug_prescription.py deleted file mode 100755 index 744bdb03ef5..00000000000 --- a/erpnext/healthcare/doctype/drug_prescription/drug_prescription.py +++ /dev/null @@ -1,36 +0,0 @@ -# -*- coding: utf-8 -*- -# Copyright (c) 2015, ESS LLP and contributors -# For license information, please see license.txt - -from __future__ import unicode_literals - -import frappe -from frappe.model.document import Document - - -class DrugPrescription(Document): - def get_quantity(self): - quantity = 0 - dosage = None - period = None - - if self.dosage: - dosage = frappe.get_doc('Prescription Dosage', self.dosage) - for item in dosage.dosage_strength: - quantity += item.strength - if self.period and self.interval: - period = frappe.get_doc('Prescription Duration', self.period) - if self.interval < period.get_days(): - quantity = quantity * (period.get_days()/self.interval) - - elif self.interval and self.interval_uom and self.period: - period = frappe.get_doc('Prescription Duration', self.period) - interval_in = self.interval_uom - if interval_in == 'Day' and self.interval < period.get_days(): - quantity = period.get_days()/self.interval - elif interval_in == 'Hour' and self.interval < period.get_hours(): - quantity = period.get_hours()/self.interval - if quantity > 0: - return quantity - else: - return 1 diff --git a/erpnext/healthcare/doctype/exercise/exercise.json b/erpnext/healthcare/doctype/exercise/exercise.json deleted file mode 100644 index 683cc6d3c31..00000000000 --- a/erpnext/healthcare/doctype/exercise/exercise.json +++ /dev/null @@ -1,62 +0,0 @@ -{ - "actions": [], - "creation": "2020-03-11 09:25:00.968572", - "doctype": "DocType", - "editable_grid": 1, - "engine": "InnoDB", - "field_order": [ - "exercise_type", - "difficulty_level", - "counts_target", - "counts_completed", - "assistance_level" - ], - "fields": [ - { - "fieldname": "exercise_type", - "fieldtype": "Link", - "in_list_view": 1, - "label": "Exercise Type", - "options": "Exercise Type", - "reqd": 1 - }, - { - "fetch_from": "exercise_type.difficulty_level", - "fieldname": "difficulty_level", - "fieldtype": "Link", - "label": "Difficulty Level", - "options": "Exercise Difficulty Level" - }, - { - "fieldname": "counts_target", - "fieldtype": "Int", - "in_list_view": 1, - "label": "Counts Target" - }, - { - "depends_on": "eval:doc.parenttype==\"Therapy\";", - "fieldname": "counts_completed", - "fieldtype": "Int", - "label": "Counts Completed", - "no_copy": 1 - }, - { - "fieldname": "assistance_level", - "fieldtype": "Select", - "label": "Assistance Level", - "options": "\nPassive\nActive Assist\nActive" - } - ], - "istable": 1, - "links": [], - "modified": "2020-11-04 18:20:25.583491", - "modified_by": "Administrator", - "module": "Healthcare", - "name": "Exercise", - "owner": "Administrator", - "permissions": [], - "quick_entry": 1, - "sort_field": "modified", - "sort_order": "DESC", - "track_changes": 1 -} \ No newline at end of file diff --git a/erpnext/healthcare/doctype/exercise/exercise.py b/erpnext/healthcare/doctype/exercise/exercise.py deleted file mode 100644 index 5d2b1f1a96d..00000000000 --- a/erpnext/healthcare/doctype/exercise/exercise.py +++ /dev/null @@ -1,12 +0,0 @@ -# -*- coding: utf-8 -*- -# Copyright (c) 2020, Frappe Technologies Pvt. Ltd. and contributors -# For license information, please see license.txt - -from __future__ import unicode_literals - -# import frappe -from frappe.model.document import Document - - -class Exercise(Document): - pass diff --git a/erpnext/healthcare/doctype/exercise_difficulty_level/exercise_difficulty_level.js b/erpnext/healthcare/doctype/exercise_difficulty_level/exercise_difficulty_level.js deleted file mode 100644 index ff51c34f3f6..00000000000 --- a/erpnext/healthcare/doctype/exercise_difficulty_level/exercise_difficulty_level.js +++ /dev/null @@ -1,8 +0,0 @@ -// Copyright (c) 2020, Frappe Technologies Pvt. Ltd. and contributors -// For license information, please see license.txt - -frappe.ui.form.on('Exercise Difficulty Level', { - // refresh: function(frm) { - - // } -}); diff --git a/erpnext/healthcare/doctype/exercise_difficulty_level/exercise_difficulty_level.json b/erpnext/healthcare/doctype/exercise_difficulty_level/exercise_difficulty_level.json deleted file mode 100644 index a6aed75e7a5..00000000000 --- a/erpnext/healthcare/doctype/exercise_difficulty_level/exercise_difficulty_level.json +++ /dev/null @@ -1,45 +0,0 @@ -{ - "actions": [], - "autoname": "field:difficulty_level", - "creation": "2020-03-29 21:12:55.835941", - "doctype": "DocType", - "editable_grid": 1, - "engine": "InnoDB", - "field_order": [ - "difficulty_level" - ], - "fields": [ - { - "fieldname": "difficulty_level", - "fieldtype": "Data", - "in_list_view": 1, - "label": "Difficulty Level", - "reqd": 1, - "unique": 1 - } - ], - "links": [], - "modified": "2020-03-31 23:14:33.554066", - "modified_by": "Administrator", - "module": "Healthcare", - "name": "Exercise Difficulty Level", - "owner": "Administrator", - "permissions": [ - { - "create": 1, - "delete": 1, - "email": 1, - "export": 1, - "print": 1, - "read": 1, - "report": 1, - "role": "System Manager", - "share": 1, - "write": 1 - } - ], - "quick_entry": 1, - "sort_field": "modified", - "sort_order": "DESC", - "track_changes": 1 -} \ No newline at end of file diff --git a/erpnext/healthcare/doctype/exercise_difficulty_level/exercise_difficulty_level.py b/erpnext/healthcare/doctype/exercise_difficulty_level/exercise_difficulty_level.py deleted file mode 100644 index bbb297275f9..00000000000 --- a/erpnext/healthcare/doctype/exercise_difficulty_level/exercise_difficulty_level.py +++ /dev/null @@ -1,12 +0,0 @@ -# -*- coding: utf-8 -*- -# Copyright (c) 2020, Frappe Technologies Pvt. Ltd. and contributors -# For license information, please see license.txt - -from __future__ import unicode_literals - -# import frappe -from frappe.model.document import Document - - -class ExerciseDifficultyLevel(Document): - pass diff --git a/erpnext/healthcare/doctype/exercise_difficulty_level/test_exercise_difficulty_level.py b/erpnext/healthcare/doctype/exercise_difficulty_level/test_exercise_difficulty_level.py deleted file mode 100644 index dcaea08aba3..00000000000 --- a/erpnext/healthcare/doctype/exercise_difficulty_level/test_exercise_difficulty_level.py +++ /dev/null @@ -1,11 +0,0 @@ -# -*- coding: utf-8 -*- -# Copyright (c) 2020, Frappe Technologies Pvt. Ltd. and Contributors -# See license.txt -from __future__ import unicode_literals - -# import frappe -import unittest - - -class TestExerciseDifficultyLevel(unittest.TestCase): - pass diff --git a/erpnext/healthcare/doctype/exercise_type/exercise_type.js b/erpnext/healthcare/doctype/exercise_type/exercise_type.js deleted file mode 100644 index 06146047eb3..00000000000 --- a/erpnext/healthcare/doctype/exercise_type/exercise_type.js +++ /dev/null @@ -1,186 +0,0 @@ -// Copyright (c) 2020, Frappe Technologies Pvt. Ltd. and contributors -// For license information, please see license.txt - -frappe.ui.form.on('Exercise Type', { - refresh: function(frm) { - let wrapper = frm.fields_dict.steps_html.wrapper; - - frm.ExerciseEditor = new erpnext.ExerciseEditor(frm, wrapper); - } -}); - -erpnext.ExerciseEditor = class ExerciseEditor { - constructor(frm, wrapper) { - this.wrapper = wrapper; - this.frm = frm; - this.make(frm, wrapper); - } - - make(frm, wrapper) { - $(this.wrapper).empty(); - - this.exercise_toolbar = $('

\ - ').appendTo(this.wrapper); - - this.exercise_cards = $('

').appendTo(this.wrapper); - - this.row = $('
').appendTo(this.wrapper); - - let me = this; - - this.exercise_toolbar.find(".btn-add") - .html(__('Add')) - .on("click", function() { - me.show_add_card_dialog(frm); - }); - - if (frm.doc.steps_table && frm.doc.steps_table.length > 0) { - this.make_cards(frm); - this.make_buttons(frm); - } - } - - make_cards(frm) { - var me = this; - $(me.exercise_cards).empty(); - - $.each(frm.doc.steps_table, function(i, step) { - $(repl(` -
-
-
- ... -

%(title)s

-

%(description)s

-
- -
-
`, {image_src: step.image, title: step.title, description: step.description, col_id: "col-"+i, card_id: "card-"+i, id: i})).appendTo(me.row); - }); - } - - make_buttons(frm) { - let me = this; - $('.btn-edit').on('click', function() { - let id = $(this).attr('data-id'); - me.show_edit_card_dialog(frm, id); - }); - - $('.btn-del').on('click', function() { - let id = $(this).attr('data-id'); - $('#card-'+id).addClass("zoom-out"); - - setTimeout(() => { - // not using grid_rows[id].remove because - // grid_rows is not defined when the table is hidden - frm.doc.steps_table.pop(id); - frm.refresh_field('steps_table'); - $('#col-'+id).remove(); - frm.dirty(); - }, 300); - }); - } - - show_add_card_dialog(frm) { - let me = this; - let d = new frappe.ui.Dialog({ - title: __('Add Exercise Step'), - fields: [ - { - "label": "Title", - "fieldname": "title", - "fieldtype": "Data", - "reqd": 1 - }, - { - "label": "Attach Image", - "fieldname": "image", - "fieldtype": "Attach Image" - }, - { - "label": "Step Description", - "fieldname": "step_description", - "fieldtype": "Long Text" - } - ], - primary_action: function() { - let data = d.get_values(); - let i = 0; - if (frm.doc.steps_table) { - i = frm.doc.steps_table.length; - } - $(repl(` -
-
-
- ... -

%(title)s

-

%(description)s

-
- -
-
`, {image_src: data.image, title: data.title, description: data.step_description, col_id: "col-"+i, card_id: "card-"+i, id: i})).appendTo(me.row); - let step = frappe.model.add_child(frm.doc, 'Exercise Type Step', 'steps_table'); - step.title = data.title; - step.image = data.image; - step.description = data.step_description; - me.make_buttons(frm); - frm.refresh_field('steps_table'); - d.hide(); - }, - primary_action_label: __('Add') - }); - d.show(); - } - - show_edit_card_dialog(frm, id) { - let new_dialog = new frappe.ui.Dialog({ - title: __("Edit Exercise Step"), - fields: [ - { - "label": "Title", - "fieldname": "title", - "fieldtype": "Data", - "reqd": 1 - }, - { - "label": "Attach Image", - "fieldname": "image", - "fieldtype": "Attach Image" - }, - { - "label": "Step Description", - "fieldname": "step_description", - "fieldtype": "Long Text" - } - ], - primary_action: () => { - let data = new_dialog.get_values(); - $('#card-'+id).find('.card-title').html(data.title); - $('#card-'+id).find('img').attr('src', data.image); - $('#card-'+id).find('.card-text').html(data.step_description); - - frm.doc.steps_table[id].title = data.title; - frm.doc.steps_table[id].image = data.image; - frm.doc.steps_table[id].description = data.step_description; - refresh_field('steps_table'); - frm.dirty(); - new_dialog.hide(); - }, - primary_action_label: __("Edit"), - }); - - new_dialog.set_values({ - title: frm.doc.steps_table[id].title, - image: frm.doc.steps_table[id].image, - step_description: frm.doc.steps_table[id].description - }); - new_dialog.show(); - } -}; diff --git a/erpnext/healthcare/doctype/exercise_type/exercise_type.json b/erpnext/healthcare/doctype/exercise_type/exercise_type.json deleted file mode 100644 index 0db9c6e796c..00000000000 --- a/erpnext/healthcare/doctype/exercise_type/exercise_type.json +++ /dev/null @@ -1,144 +0,0 @@ -{ - "actions": [], - "creation": "2020-03-29 21:37:03.366344", - "doctype": "DocType", - "editable_grid": 1, - "engine": "InnoDB", - "field_order": [ - "exercise_name", - "body_parts", - "column_break_3", - "difficulty_level", - "section_break_5", - "description", - "section_break_7", - "exercise_steps", - "column_break_9", - "exercise_video", - "section_break_11", - "steps_html", - "section_break_13", - "steps_table" - ], - "fields": [ - { - "fieldname": "exercise_name", - "fieldtype": "Data", - "in_list_view": 1, - "label": "Exercise Name", - "reqd": 1 - }, - { - "fieldname": "difficulty_level", - "fieldtype": "Link", - "in_list_view": 1, - "label": "Difficulty Level", - "options": "Exercise Difficulty Level" - }, - { - "fieldname": "column_break_3", - "fieldtype": "Column Break" - }, - { - "fieldname": "section_break_5", - "fieldtype": "Section Break" - }, - { - "fieldname": "description", - "fieldtype": "Long Text", - "label": "Description" - }, - { - "fieldname": "section_break_7", - "fieldtype": "Section Break" - }, - { - "fieldname": "exercise_steps", - "fieldtype": "Attach", - "label": "Exercise Instructions" - }, - { - "fieldname": "exercise_video", - "fieldtype": "Link", - "label": "Exercise Video", - "options": "Video" - }, - { - "fieldname": "column_break_9", - "fieldtype": "Column Break" - }, - { - "fieldname": "steps_html", - "fieldtype": "HTML", - "label": "Steps" - }, - { - "fieldname": "steps_table", - "fieldtype": "Table", - "hidden": 1, - "label": "Steps Table", - "options": "Exercise Type Step" - }, - { - "fieldname": "section_break_11", - "fieldtype": "Section Break", - "label": "Exercise Steps" - }, - { - "fieldname": "section_break_13", - "fieldtype": "Section Break" - }, - { - "fieldname": "body_parts", - "fieldtype": "Table MultiSelect", - "label": "Body Parts", - "options": "Body Part Link" - } - ], - "links": [], - "modified": "2020-04-21 13:05:36.555060", - "modified_by": "Administrator", - "module": "Healthcare", - "name": "Exercise Type", - "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": "Healthcare Administrator", - "share": 1, - "write": 1 - }, - { - "email": 1, - "export": 1, - "print": 1, - "read": 1, - "report": 1, - "role": "Physician", - "share": 1, - "write": 1 - } - ], - "quick_entry": 1, - "sort_field": "modified", - "sort_order": "DESC", - "track_changes": 1 -} \ No newline at end of file diff --git a/erpnext/healthcare/doctype/exercise_type/exercise_type.py b/erpnext/healthcare/doctype/exercise_type/exercise_type.py deleted file mode 100644 index 48eb6ba2d81..00000000000 --- a/erpnext/healthcare/doctype/exercise_type/exercise_type.py +++ /dev/null @@ -1,16 +0,0 @@ -# -*- coding: utf-8 -*- -# Copyright (c) 2020, Frappe Technologies Pvt. Ltd. and contributors -# For license information, please see license.txt - -from __future__ import unicode_literals - -# import frappe -from frappe.model.document import Document - - -class ExerciseType(Document): - def autoname(self): - if self.difficulty_level: - self.name = ' - '.join(filter(None, [self.exercise_name, self.difficulty_level])) - else: - self.name = self.exercise_name diff --git a/erpnext/healthcare/doctype/exercise_type/test_exercise_type.py b/erpnext/healthcare/doctype/exercise_type/test_exercise_type.py deleted file mode 100644 index 583aea911ae..00000000000 --- a/erpnext/healthcare/doctype/exercise_type/test_exercise_type.py +++ /dev/null @@ -1,11 +0,0 @@ -# -*- coding: utf-8 -*- -# Copyright (c) 2020, Frappe Technologies Pvt. Ltd. and Contributors -# See license.txt -from __future__ import unicode_literals - -# import frappe -import unittest - - -class TestExerciseType(unittest.TestCase): - pass diff --git a/erpnext/healthcare/doctype/exercise_type_step/exercise_type_step.py b/erpnext/healthcare/doctype/exercise_type_step/exercise_type_step.py deleted file mode 100644 index 412ef3225ed..00000000000 --- a/erpnext/healthcare/doctype/exercise_type_step/exercise_type_step.py +++ /dev/null @@ -1,12 +0,0 @@ -# -*- coding: utf-8 -*- -# Copyright (c) 2020, Frappe Technologies Pvt. Ltd. and contributors -# For license information, please see license.txt - -from __future__ import unicode_literals - -# import frappe -from frappe.model.document import Document - - -class ExerciseTypeStep(Document): - pass diff --git a/erpnext/healthcare/doctype/fee_validity/fee_validity.js b/erpnext/healthcare/doctype/fee_validity/fee_validity.js deleted file mode 100644 index 7ea22136192..00000000000 --- a/erpnext/healthcare/doctype/fee_validity/fee_validity.js +++ /dev/null @@ -1,5 +0,0 @@ -// Copyright (c) 2016, ESS LLP and contributors -// For license information, please see license.txt - -frappe.ui.form.on('Fee Validity', { -}); diff --git a/erpnext/healthcare/doctype/fee_validity/fee_validity.json b/erpnext/healthcare/doctype/fee_validity/fee_validity.json deleted file mode 100644 index d76b42e6836..00000000000 --- a/erpnext/healthcare/doctype/fee_validity/fee_validity.json +++ /dev/null @@ -1,134 +0,0 @@ -{ - "actions": [], - "allow_copy": 1, - "allow_import": 1, - "beta": 1, - "creation": "2017-01-05 10:56:29.564806", - "doctype": "DocType", - "document_type": "Setup", - "editable_grid": 1, - "engine": "InnoDB", - "field_order": [ - "practitioner", - "patient", - "column_break_3", - "status", - "section_break_5", - "section_break_3", - "max_visits", - "visited", - "ref_appointments", - "column_break_6", - "start_date", - "valid_till" - ], - "fields": [ - { - "fieldname": "practitioner", - "fieldtype": "Link", - "in_list_view": 1, - "label": "Healthcare Practitioner", - "options": "Healthcare Practitioner", - "read_only": 1, - "reqd": 1, - "search_index": 1 - }, - { - "fieldname": "patient", - "fieldtype": "Link", - "in_list_view": 1, - "label": "Patient", - "options": "Patient", - "read_only": 1, - "reqd": 1, - "search_index": 1 - }, - { - "fieldname": "visited", - "fieldtype": "Int", - "label": "Visits Completed", - "read_only": 1 - }, - { - "fieldname": "valid_till", - "fieldtype": "Date", - "label": "Valid Till", - "read_only": 1 - }, - { - "fieldname": "section_break_3", - "fieldtype": "Section Break", - "label": "Validity", - "read_only": 1 - }, - { - "fieldname": "column_break_6", - "fieldtype": "Column Break" - }, - { - "fieldname": "max_visits", - "fieldtype": "Int", - "label": "Max number of visit", - "read_only": 1 - }, - { - "fieldname": "column_break_3", - "fieldtype": "Column Break" - }, - { - "fieldname": "status", - "fieldtype": "Select", - "in_list_view": 1, - "in_standard_filter": 1, - "label": "Status", - "options": "Completed\nPending", - "read_only": 1 - }, - { - "fetch_from": "ref_appointment.appointment_date", - "fieldname": "start_date", - "fieldtype": "Date", - "label": "Start Date", - "read_only": 1 - }, - { - "fieldname": "ref_appointments", - "fieldtype": "Table MultiSelect", - "label": "Reference Appointments", - "options": "Fee Validity Reference", - "read_only": 1 - }, - { - "collapsible": 1, - "fieldname": "section_break_5", - "fieldtype": "Section Break" - } - ], - "in_create": 1, - "links": [], - "modified": "2021-08-26 10:51:05.609349", - "modified_by": "Administrator", - "module": "Healthcare", - "name": "Fee Validity", - "owner": "Administrator", - "permissions": [ - { - "create": 1, - "delete": 1, - "email": 1, - "export": 1, - "print": 1, - "read": 1, - "report": 1, - "role": "Healthcare Administrator", - "share": 1, - "write": 1 - } - ], - "quick_entry": 1, - "restrict_to_domain": "Healthcare", - "search_fields": "practitioner, patient", - "sort_field": "modified", - "sort_order": "DESC", - "title_field": "practitioner" -} \ No newline at end of file diff --git a/erpnext/healthcare/doctype/fee_validity/fee_validity.py b/erpnext/healthcare/doctype/fee_validity/fee_validity.py deleted file mode 100644 index aa30becd337..00000000000 --- a/erpnext/healthcare/doctype/fee_validity/fee_validity.py +++ /dev/null @@ -1,56 +0,0 @@ -# -*- coding: utf-8 -*- -# Copyright (c) 2015, ESS LLP and contributors -# For license information, please see license.txt - -from __future__ import unicode_literals - -import datetime - -import frappe -from frappe.model.document import Document -from frappe.utils import getdate - - -class FeeValidity(Document): - def validate(self): - self.update_status() - - def update_status(self): - if self.visited >= self.max_visits: - self.status = 'Completed' - else: - self.status = 'Pending' - - -def create_fee_validity(appointment): - if not check_is_new_patient(appointment): - return - - fee_validity = frappe.new_doc('Fee Validity') - fee_validity.practitioner = appointment.practitioner - fee_validity.patient = appointment.patient - fee_validity.max_visits = frappe.db.get_single_value('Healthcare Settings', 'max_visits') or 1 - valid_days = frappe.db.get_single_value('Healthcare Settings', 'valid_days') or 1 - fee_validity.visited = 0 - fee_validity.start_date = getdate(appointment.appointment_date) - fee_validity.valid_till = getdate(appointment.appointment_date) + datetime.timedelta(days=int(valid_days)) - fee_validity.save(ignore_permissions=True) - return fee_validity - -def check_is_new_patient(appointment): - validity_exists = frappe.db.exists('Fee Validity', { - 'practitioner': appointment.practitioner, - 'patient': appointment.patient - }) - if validity_exists: - return False - - appointment_exists = frappe.db.get_all('Patient Appointment', { - 'name': ('!=', appointment.name), - 'status': ('!=', 'Cancelled'), - 'patient': appointment.patient, - 'practitioner': appointment.practitioner - }) - if len(appointment_exists) and appointment_exists[0]: - return False - return True diff --git a/erpnext/healthcare/doctype/fee_validity/test_fee_validity.py b/erpnext/healthcare/doctype/fee_validity/test_fee_validity.py deleted file mode 100644 index ce1947f5bad..00000000000 --- a/erpnext/healthcare/doctype/fee_validity/test_fee_validity.py +++ /dev/null @@ -1,56 +0,0 @@ -# -*- coding: utf-8 -*- -# Copyright (c) 2015, ESS LLP and Contributors -# See license.txt -from __future__ import unicode_literals - -import unittest - -import frappe -from frappe.utils import add_days, nowdate - -from erpnext.accounts.doctype.pos_profile.test_pos_profile import make_pos_profile -from erpnext.healthcare.doctype.patient_appointment.test_patient_appointment import ( - create_appointment, - create_healthcare_docs, - create_healthcare_service_items, -) - -test_dependencies = ["Company"] - -class TestFeeValidity(unittest.TestCase): - def setUp(self): - frappe.db.sql("""delete from `tabPatient Appointment`""") - frappe.db.sql("""delete from `tabFee Validity`""") - frappe.db.sql("""delete from `tabPatient`""") - make_pos_profile() - - def test_fee_validity(self): - item = create_healthcare_service_items() - healthcare_settings = frappe.get_single("Healthcare Settings") - healthcare_settings.enable_free_follow_ups = 1 - healthcare_settings.max_visits = 1 - healthcare_settings.valid_days = 7 - healthcare_settings.automate_appointment_invoicing = 1 - healthcare_settings.op_consulting_charge_item = item - healthcare_settings.save(ignore_permissions=True) - patient, practitioner = create_healthcare_docs() - - # For first appointment, invoice is generated. First appointment not considered in fee validity - appointment = create_appointment(patient, practitioner, nowdate()) - invoiced = frappe.db.get_value("Patient Appointment", appointment.name, "invoiced") - self.assertEqual(invoiced, 1) - - # appointment should not be invoiced as it is within fee validity - appointment = create_appointment(patient, practitioner, add_days(nowdate(), 4)) - invoiced = frappe.db.get_value("Patient Appointment", appointment.name, "invoiced") - self.assertEqual(invoiced, 0) - - # appointment should be invoiced as it is within fee validity but the max_visits are exceeded - appointment = create_appointment(patient, practitioner, add_days(nowdate(), 5), invoice=1) - invoiced = frappe.db.get_value("Patient Appointment", appointment.name, "invoiced") - self.assertEqual(invoiced, 1) - - # appointment should be invoiced as it is not within fee validity and the max_visits are exceeded - appointment = create_appointment(patient, practitioner, add_days(nowdate(), 10), invoice=1) - invoiced = frappe.db.get_value("Patient Appointment", appointment.name, "invoiced") - self.assertEqual(invoiced, 1) diff --git a/erpnext/healthcare/doctype/fee_validity_reference/fee_validity_reference.json b/erpnext/healthcare/doctype/fee_validity_reference/fee_validity_reference.json deleted file mode 100644 index 40f128e973d..00000000000 --- a/erpnext/healthcare/doctype/fee_validity_reference/fee_validity_reference.json +++ /dev/null @@ -1,32 +0,0 @@ -{ - "actions": [], - "creation": "2020-03-13 16:08:42.859996", - "doctype": "DocType", - "editable_grid": 1, - "engine": "InnoDB", - "field_order": [ - "appointment" - ], - "fields": [ - { - "fieldname": "appointment", - "fieldtype": "Link", - "in_list_view": 1, - "label": "Patient Appointment", - "options": "Patient Appointment", - "reqd": 1 - } - ], - "istable": 1, - "links": [], - "modified": "2020-03-15 00:27:02.076470", - "modified_by": "Administrator", - "module": "Healthcare", - "name": "Fee Validity Reference", - "owner": "Administrator", - "permissions": [], - "quick_entry": 1, - "sort_field": "modified", - "sort_order": "DESC", - "track_changes": 1 -} \ No newline at end of file diff --git a/erpnext/healthcare/doctype/fee_validity_reference/fee_validity_reference.py b/erpnext/healthcare/doctype/fee_validity_reference/fee_validity_reference.py deleted file mode 100644 index c03978aad11..00000000000 --- a/erpnext/healthcare/doctype/fee_validity_reference/fee_validity_reference.py +++ /dev/null @@ -1,12 +0,0 @@ -# -*- coding: utf-8 -*- -# Copyright (c) 2020, Frappe Technologies Pvt. Ltd. and contributors -# For license information, please see license.txt - -from __future__ import unicode_literals - -# import frappe -from frappe.model.document import Document - - -class FeeValidityReference(Document): - pass diff --git a/erpnext/healthcare/doctype/healthcare.py b/erpnext/healthcare/doctype/healthcare.py deleted file mode 100644 index f8e008e7d38..00000000000 --- a/erpnext/healthcare/doctype/healthcare.py +++ /dev/null @@ -1,6 +0,0 @@ -from __future__ import unicode_literals - - -def get_data(): - - return [] diff --git a/erpnext/healthcare/doctype/healthcare_practitioner/healthcare_practitioner.js b/erpnext/healthcare/doctype/healthcare_practitioner/healthcare_practitioner.js deleted file mode 100644 index 44c399856c8..00000000000 --- a/erpnext/healthcare/doctype/healthcare_practitioner/healthcare_practitioner.js +++ /dev/null @@ -1,144 +0,0 @@ -// Copyright (c) 2016, ESS LLP and contributors -// For license information, please see license.txt - -frappe.ui.form.on('Healthcare Practitioner', { - setup: function(frm) { - frm.set_query('account', 'accounts', function(doc, cdt, cdn) { - let d = locals[cdt][cdn]; - return { - filters: { - 'root_type': 'Income', - 'company': d.company, - 'is_group': 0 - } - }; - }); - }, - refresh: function(frm) { - frappe.dynamic_link = {doc: frm.doc, fieldname: 'name', doctype: 'Healthcare Practitioner'}; - - if (!frm.is_new()) { - frappe.contacts.render_address_and_contact(frm); - } else { - frappe.contacts.clear_address_and_contact(frm); - } - - frm.set_query('service_unit', 'practitioner_schedules', function(){ - return { - filters: { - 'is_group': false, - 'allow_appointments': true - } - }; - }); - - set_query_service_item(frm, 'inpatient_visit_charge_item'); - set_query_service_item(frm, 'op_consulting_charge_item'); - } -}); - -let set_query_service_item = function(frm, service_item_field) { - frm.set_query(service_item_field, function() { - return { - filters: { - 'is_sales_item': 1, - 'is_stock_item': 0 - } - }; - }); -}; - -frappe.ui.form.on('Healthcare Practitioner', 'user_id',function(frm) { - if (frm.doc.user_id) { - frappe.call({ - 'method': 'frappe.client.get', - args: { - doctype: 'User', - name: frm.doc.user_id - }, - callback: function (data) { - - frappe.model.get_value('Employee', {'user_id': frm.doc.user_id}, 'name', - function(data) { - if (data) { - if (!frm.doc.employee || frm.doc.employee != data.name) - frappe.model.set_value(frm.doctype, frm.docname, 'employee', data.name); - } else { - frappe.model.set_value(frm.doctype, frm.docname, 'employee', ''); - } - } - ); - - if (!frm.doc.first_name || frm.doc.first_name != data.message.first_name) - frappe.model.set_value(frm.doctype,frm.docname, 'first_name', data.message.first_name); - if (!frm.doc.middle_name || frm.doc.middle_name != data.message.middle_name) - frappe.model.set_value(frm.doctype,frm.docname, 'middle_name', data.message.middle_name); - if (!frm.doc.last_name || frm.doc.last_name != data.message.last_name) - frappe.model.set_value(frm.doctype,frm.docname, 'last_name', data.message.last_name); - if (!frm.doc.mobile_phone || frm.doc.mobile_phone != data.message.mobile_no) - frappe.model.set_value(frm.doctype,frm.docname, 'mobile_phone', data.message.mobile_no); - } - }); - } -}); - -frappe.ui.form.on('Healthcare Practitioner', 'employee', function(frm) { - if (frm.doc.employee){ - frappe.call({ - 'method': 'frappe.client.get', - args: { - doctype: 'Employee', - name: frm.doc.employee - }, - callback: function (data) { - if (!frm.doc.user_id || frm.doc.user_id != data.message.user_id) - frm.set_value('user_id', data.message.user_id); - if (!frm.doc.designation || frm.doc.designation != data.message.designation) - frappe.model.set_value(frm.doctype,frm.docname, 'designation', data.message.designation); - if (!frm.doc.first_name || !frm.doc.user_id){ - frappe.model.set_value(frm.doctype,frm.docname, 'first_name', data.message.first_name); - frappe.model.set_value(frm.doctype,frm.docname, 'middle_name', ''); - frappe.model.set_value(frm.doctype,frm.docname, 'last_name', data.message.last_name); - } - if (!frm.doc.mobile_phone || !frm.doc.user_id) - frappe.model.set_value(frm.doctype,frm.docname, 'mobile_phone', data.message.cell_number); - if (!frm.doc.address || frm.doc.address != data.message.current_address) - frappe.model.set_value(frm.doctype,frm.docname, 'address', data.message.current_address); - } - }); - } -}); - -frappe.tour['Healthcare Practitioner'] = [ - { - fieldname: 'employee', - title: __('Employee'), - description: __('If you want to track Payroll and other HRMS operations for a Practitoner, create an Employee and link it here.') - }, - { - fieldname: 'practitioner_schedules', - title: __('Practitioner Schedules'), - description: __('Set the Practitioner Schedule you just created. This will be used while booking appointments.') - }, - { - fieldname: 'op_consulting_charge_item', - title: __('Out Patient Consulting Charge Item'), - description: __('Create a service item for Out Patient Consulting.') - }, - { - fieldname: 'inpatient_visit_charge_item', - title: __('Inpatient Visit Charge Item'), - description: __('If this Healthcare Practitioner works for the In-Patient Department, create a service item for Inpatient Visits.') - }, - { - fieldname: 'op_consulting_charge', - title: __('Out Patient Consulting Charge'), - description: __('Set the Out Patient Consulting Charge for this Practitioner.') - - }, - { - fieldname: 'inpatient_visit_charge', - title: __('Inpatient Visit Charge'), - description: __('If this Healthcare Practitioner also works for the In-Patient Department, set the inpatient visit charge for this Practitioner.') - } -]; diff --git a/erpnext/healthcare/doctype/healthcare_practitioner/healthcare_practitioner.json b/erpnext/healthcare/doctype/healthcare_practitioner/healthcare_practitioner.json deleted file mode 100644 index cb455eb5014..00000000000 --- a/erpnext/healthcare/doctype/healthcare_practitioner/healthcare_practitioner.json +++ /dev/null @@ -1,336 +0,0 @@ -{ - "actions": [], - "allow_import": 1, - "allow_rename": 1, - "autoname": "naming_series:", - "beta": 1, - "creation": "2016-02-23 11:20:53.565119", - "doctype": "DocType", - "document_type": "Setup", - "engine": "InnoDB", - "field_order": [ - "basic_details_section", - "naming_series", - "first_name", - "middle_name", - "last_name", - "practitioner_name", - "gender", - "image", - "column_break_7", - "status", - "mobile_phone", - "residence_phone", - "office_phone", - "employee_and_user_details_section", - "employee", - "department", - "designation", - "column_break_17", - "user_id", - "hospital", - "appointments", - "practitioner_schedules", - "charges", - "op_consulting_charge_item", - "op_consulting_charge", - "column_break_18", - "inpatient_visit_charge_item", - "inpatient_visit_charge", - "account_details", - "default_currency", - "accounts", - "address_and_contacts_section", - "address_html", - "column_break_19", - "contact_html" - ], - "fields": [ - { - "fieldname": "first_name", - "fieldtype": "Data", - "label": "First Name", - "no_copy": 1, - "reqd": 1 - }, - { - "fieldname": "middle_name", - "fieldtype": "Data", - "label": "Middle Name (Optional)", - "no_copy": 1 - }, - { - "fieldname": "last_name", - "fieldtype": "Data", - "label": "Last Name", - "no_copy": 1 - }, - { - "fieldname": "image", - "fieldtype": "Attach Image", - "hidden": 1, - "label": "Image", - "no_copy": 1, - "print_hide": 1 - }, - { - "fieldname": "employee", - "fieldtype": "Link", - "label": "Employee", - "options": "Employee" - }, - { - "fieldname": "user_id", - "fieldtype": "Link", - "label": "User", - "options": "User", - "search_index": 1 - }, - { - "fetch_from": "employee", - "fieldname": "designation", - "fieldtype": "Link", - "ignore_user_permissions": 1, - "in_list_view": 1, - "in_standard_filter": 1, - "label": "Designation", - "options": "Designation", - "read_only": 1 - }, - { - "fieldname": "department", - "fieldtype": "Link", - "ignore_user_permissions": 1, - "in_standard_filter": 1, - "label": "Medical Department", - "options": "Medical Department" - }, - { - "fieldname": "column_break_7", - "fieldtype": "Column Break" - }, - { - "fieldname": "hospital", - "fieldtype": "Data", - "label": "Hospital" - }, - { - "fieldname": "mobile_phone", - "fieldtype": "Data", - "in_list_view": 1, - "label": "Mobile" - }, - { - "fieldname": "residence_phone", - "fieldtype": "Data", - "label": "Phone (R)" - }, - { - "fieldname": "office_phone", - "fieldtype": "Data", - "in_list_view": 1, - "label": "Phone (Office)" - }, - { - "collapsible": 1, - "fieldname": "appointments", - "fieldtype": "Section Break", - "label": "Appointments" - }, - { - "fieldname": "practitioner_schedules", - "fieldtype": "Table", - "label": "Practitioner Schedules", - "options": "Practitioner Service Unit Schedule" - }, - { - "collapsible": 1, - "fieldname": "charges", - "fieldtype": "Section Break", - "label": "Charges" - }, - { - "fieldname": "op_consulting_charge_item", - "fieldtype": "Link", - "label": "Out Patient Consulting Charge Item", - "options": "Item" - }, - { - "fieldname": "op_consulting_charge", - "fieldtype": "Currency", - "label": "Out Patient Consulting Charge", - "mandatory_depends_on": "op_consulting_charge_item", - "options": "Currency" - }, - { - "fieldname": "column_break_18", - "fieldtype": "Column Break" - }, - { - "fieldname": "inpatient_visit_charge_item", - "fieldtype": "Link", - "label": "Inpatient Visit Charge Item", - "options": "Item" - }, - { - "fieldname": "inpatient_visit_charge", - "fieldtype": "Currency", - "label": "Inpatient Visit Charge", - "mandatory_depends_on": "inpatient_visit_charge_item" - }, - { - "depends_on": "eval: !doc.__islocal", - "fieldname": "address_html", - "fieldtype": "HTML", - "label": "Address HTML", - "no_copy": 1, - "print_hide": 1, - "report_hide": 1 - }, - { - "fieldname": "column_break_19", - "fieldtype": "Column Break" - }, - { - "depends_on": "eval: !doc.__islocal", - "fieldname": "contact_html", - "fieldtype": "HTML", - "label": "Contact HTML", - "no_copy": 1, - "print_hide": 1, - "report_hide": 1 - }, - { - "collapsible": 1, - "fieldname": "account_details", - "fieldtype": "Section Break", - "label": "Account Details" - }, - { - "fieldname": "accounts", - "fieldtype": "Table", - "label": "Income Account", - "options": "Party Account" - }, - { - "fieldname": "default_currency", - "fieldtype": "Link", - "hidden": 1, - "label": "Default Currency", - "no_copy": 1, - "options": "Currency", - "print_hide": 1, - "report_hide": 1 - }, - { - "bold": 1, - "fieldname": "practitioner_name", - "fieldtype": "Data", - "in_global_search": 1, - "in_list_view": 1, - "in_standard_filter": 1, - "label": "Full Name", - "no_copy": 1, - "read_only": 1, - "search_index": 1 - }, - { - "fieldname": "naming_series", - "fieldtype": "Select", - "label": "Series", - "no_copy": 1, - "options": "HLC-PRAC-.YYYY.-", - "report_hide": 1, - "set_only_once": 1 - }, - { - "fieldname": "gender", - "fieldtype": "Link", - "label": "Gender", - "options": "Gender" - }, - { - "fieldname": "employee_and_user_details_section", - "fieldtype": "Section Break", - "label": "Employee and User Details" - }, - { - "fieldname": "column_break_17", - "fieldtype": "Column Break" - }, - { - "default": "Active", - "fieldname": "status", - "fieldtype": "Select", - "in_list_view": 1, - "label": "Status", - "options": "\nActive\nDisabled", - "reqd": 1 - }, - { - "fieldname": "basic_details_section", - "fieldtype": "Section Break", - "label": "Basic Details" - }, - { - "collapsible": 1, - "depends_on": "eval: !doc.__islocal", - "fieldname": "address_and_contacts_section", - "fieldtype": "Section Break", - "label": "Address and Contacts" - } - ], - "image_field": "image", - "links": [], - "modified": "2021-08-24 10:42:08.513054", - "modified_by": "Administrator", - "module": "Healthcare", - "name": "Healthcare Practitioner", - "owner": "Administrator", - "permissions": [ - { - "create": 1, - "email": 1, - "print": 1, - "read": 1, - "report": 1, - "role": "Laboratory User", - "select": 1, - "share": 1, - "write": 1 - }, - { - "create": 1, - "delete": 1, - "email": 1, - "export": 1, - "print": 1, - "read": 1, - "report": 1, - "role": "Physician", - "select": 1, - "share": 1, - "write": 1 - }, - { - "create": 1, - "delete": 1, - "email": 1, - "export": 1, - "print": 1, - "read": 1, - "report": 1, - "role": "Nursing User", - "select": 1, - "share": 1, - "write": 1 - } - ], - "restrict_to_domain": "Healthcare", - "search_fields": "practitioner_name, mobile_phone, office_phone", - "show_name_in_global_search": 1, - "sort_field": "modified", - "sort_order": "DESC", - "title_field": "practitioner_name", - "track_changes": 1 -} \ No newline at end of file diff --git a/erpnext/healthcare/doctype/healthcare_practitioner/healthcare_practitioner.py b/erpnext/healthcare/doctype/healthcare_practitioner/healthcare_practitioner.py deleted file mode 100644 index 4550e7ab4c2..00000000000 --- a/erpnext/healthcare/doctype/healthcare_practitioner/healthcare_practitioner.py +++ /dev/null @@ -1,88 +0,0 @@ -# -*- coding: utf-8 -*- -# Copyright (c) 2015, ESS LLP and contributors -# For license information, please see license.txt - -from __future__ import unicode_literals - -import frappe -from frappe import _ -from frappe.contacts.address_and_contact import ( - delete_contact_and_address, - load_address_and_contact, -) -from frappe.model.document import Document -from frappe.model.naming import append_number_if_name_exists - -from erpnext.accounts.party import validate_party_accounts - - -class HealthcarePractitioner(Document): - def onload(self): - load_address_and_contact(self) - - def autoname(self): - # concat first and last name - self.name = self.practitioner_name - - if frappe.db.exists('Healthcare Practitioner', self.name): - self.name = append_number_if_name_exists('Contact', self.name) - - def validate(self): - self.set_full_name() - validate_party_accounts(self) - if self.inpatient_visit_charge_item: - validate_service_item(self.inpatient_visit_charge_item, 'Configure a service Item for Inpatient Consulting Charge Item') - if self.op_consulting_charge_item: - validate_service_item(self.op_consulting_charge_item, 'Configure a service Item for Out Patient Consulting Charge Item') - - if self.user_id: - self.validate_user_id() - else: - existing_user_id = frappe.db.get_value('Healthcare Practitioner', self.name, 'user_id') - if existing_user_id: - frappe.permissions.remove_user_permission( - 'Healthcare Practitioner', self.name, existing_user_id) - - def on_update(self): - if self.user_id: - frappe.permissions.add_user_permission('Healthcare Practitioner', self.name, self.user_id) - - def set_full_name(self): - if self.last_name: - self.practitioner_name = ' '.join(filter(None, [self.first_name, self.last_name])) - else: - self.practitioner_name = self.first_name - - def validate_user_id(self): - if not frappe.db.exists('User', self.user_id): - frappe.throw(_('User {0} does not exist').format(self.user_id)) - elif not frappe.db.exists('User', self.user_id, 'enabled'): - frappe.throw(_('User {0} is disabled').format(self.user_id)) - - # check duplicate - practitioner = frappe.db.exists('Healthcare Practitioner', { - 'user_id': self.user_id, - 'name': ('!=', self.name) - }) - if practitioner: - frappe.throw(_('User {0} is already assigned to Healthcare Practitioner {1}').format( - self.user_id, practitioner)) - - def on_trash(self): - delete_contact_and_address('Healthcare Practitioner', self.name) - -def validate_service_item(item, msg): - if frappe.db.get_value('Item', item, 'is_stock_item'): - frappe.throw(_(msg)) - -@frappe.whitelist() -@frappe.validate_and_sanitize_search_inputs -def get_practitioner_list(doctype, txt, searchfield, start, page_len, filters=None): - fields = ['name', 'practitioner_name', 'mobile_phone'] - - filters = { - 'name': ('like', '%%%s%%' % txt) - } - - return frappe.get_all('Healthcare Practitioner', fields = fields, - filters = filters, start=start, page_length=page_len, order_by='name, practitioner_name', as_list=1) diff --git a/erpnext/healthcare/doctype/healthcare_practitioner/healthcare_practitioner_dashboard.py b/erpnext/healthcare/doctype/healthcare_practitioner/healthcare_practitioner_dashboard.py deleted file mode 100644 index 8e0292e97c2..00000000000 --- a/erpnext/healthcare/doctype/healthcare_practitioner/healthcare_practitioner_dashboard.py +++ /dev/null @@ -1,21 +0,0 @@ -from __future__ import unicode_literals - -from frappe import _ - - -def get_data(): - return { - 'heatmap': True, - 'heatmap_message': _('This is based on transactions against this Healthcare Practitioner.'), - 'fieldname': 'practitioner', - 'transactions': [ - { - 'label': _('Appointments and Patient Encounters'), - 'items': ['Patient Appointment', 'Patient Encounter', 'Fee Validity'] - }, - { - 'label': _('Consultation'), - 'items': ['Clinical Procedure', 'Lab Test'] - } - ] - } diff --git a/erpnext/healthcare/doctype/healthcare_practitioner/test_healthcare_practitioner.py b/erpnext/healthcare/doctype/healthcare_practitioner/test_healthcare_practitioner.py deleted file mode 100644 index 214bcd287aa..00000000000 --- a/erpnext/healthcare/doctype/healthcare_practitioner/test_healthcare_practitioner.py +++ /dev/null @@ -1,10 +0,0 @@ -# -*- coding: utf-8 -*- -# Copyright (c) 2018, Frappe Technologies Pvt. Ltd. and Contributors -# See license.txt -from __future__ import unicode_literals - -import unittest - - -class TestHealthcarePractitioner(unittest.TestCase): - pass diff --git a/erpnext/healthcare/doctype/healthcare_schedule_time_slot/healthcare_schedule_time_slot.json b/erpnext/healthcare/doctype/healthcare_schedule_time_slot/healthcare_schedule_time_slot.json deleted file mode 100644 index cf54e821997..00000000000 --- a/erpnext/healthcare/doctype/healthcare_schedule_time_slot/healthcare_schedule_time_slot.json +++ /dev/null @@ -1,136 +0,0 @@ -{ - "allow_copy": 0, - "allow_guest_to_view": 0, - "allow_import": 0, - "allow_rename": 0, - "beta": 1, - "creation": "2017-05-03 17:27:07.466088", - "custom": 0, - "docstatus": 0, - "doctype": "DocType", - "document_type": "", - "editable_grid": 1, - "engine": "InnoDB", - "fields": [ - { - "allow_bulk_edit": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "day", - "fieldtype": "Select", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 1, - "in_standard_filter": 0, - "label": "Day", - "length": 0, - "no_copy": 0, - "options": "Sunday\nMonday\nTuesday\nWednesday\nThursday\nFriday\nSaturday", - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 1, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 - }, - { - "allow_bulk_edit": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "from_time", - "fieldtype": "Time", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 1, - "in_standard_filter": 0, - "label": "From Time", - "length": 0, - "no_copy": 0, - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 1, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 - }, - { - "allow_bulk_edit": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "to_time", - "fieldtype": "Time", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 1, - "in_standard_filter": 0, - "label": "To Time", - "length": 0, - "no_copy": 0, - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 1, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 - } - ], - "has_web_view": 0, - "hide_heading": 0, - "hide_toolbar": 0, - "idx": 0, - "image_view": 0, - "in_create": 0, - "is_submittable": 0, - "issingle": 0, - "istable": 1, - "max_attachments": 0, - "modified": "2020-09-18 17:26:09.703215", - "modified_by": "Administrator", - "module": "Healthcare", - "name": "Healthcare Schedule Time Slot", - "name_case": "", - "owner": "Administrator", - "permissions": [], - "quick_entry": 1, - "read_only": 0, - "read_only_onload": 0, - "restrict_to_domain": "Healthcare", - "show_name_in_global_search": 0, - "sort_field": "modified", - "sort_order": "DESC", - "track_changes": 1, - "track_seen": 0 -} \ No newline at end of file diff --git a/erpnext/healthcare/doctype/healthcare_schedule_time_slot/healthcare_schedule_time_slot.py b/erpnext/healthcare/doctype/healthcare_schedule_time_slot/healthcare_schedule_time_slot.py deleted file mode 100644 index 721da24adc5..00000000000 --- a/erpnext/healthcare/doctype/healthcare_schedule_time_slot/healthcare_schedule_time_slot.py +++ /dev/null @@ -1,11 +0,0 @@ -# -*- coding: utf-8 -*- -# Copyright (c) 2018, Frappe Technologies Pvt. Ltd. and contributors -# For license information, please see license.txt - -from __future__ import unicode_literals - -from frappe.model.document import Document - - -class HealthcareScheduleTimeSlot(Document): - pass diff --git a/erpnext/healthcare/doctype/healthcare_service_unit/healthcare_service_unit.js b/erpnext/healthcare/doctype/healthcare_service_unit/healthcare_service_unit.js deleted file mode 100644 index 2d1caf7efc7..00000000000 --- a/erpnext/healthcare/doctype/healthcare_service_unit/healthcare_service_unit.js +++ /dev/null @@ -1,60 +0,0 @@ -// Copyright (c) 2018, Frappe Technologies Pvt. Ltd. and contributors -// For license information, please see license.txt - -frappe.ui.form.on('Healthcare Service Unit', { - onload: function(frm) { - frm.list_route = 'Tree/Healthcare Service Unit'; - - // get query select healthcare service unit - frm.fields_dict['parent_healthcare_service_unit'].get_query = function(doc) { - return { - filters: [ - ['Healthcare Service Unit', 'is_group', '=', 1], - ['Healthcare Service Unit', 'name', '!=', doc.healthcare_service_unit_name] - ] - }; - }; - }, - refresh: function(frm) { - frm.trigger('set_root_readonly'); - frm.set_df_property('service_unit_type', 'reqd', 1); - frm.add_custom_button(__('Healthcare Service Unit Tree'), function() { - frappe.set_route('Tree', 'Healthcare Service Unit'); - }); - - frm.set_query('warehouse', function() { - return { - filters: { - 'company': frm.doc.company - } - }; - }); - }, - set_root_readonly: function(frm) { - // read-only for root healthcare service unit - frm.set_intro(''); - if (!frm.doc.parent_healthcare_service_unit) { - frm.set_read_only(); - frm.set_intro(__('This is a root healthcare service unit and cannot be edited.'), true); - } - }, - allow_appointments: function(frm) { - if (!frm.doc.allow_appointments) { - frm.set_value('overlap_appointments', false); - } - }, - is_group: function(frm) { - if (frm.doc.is_group == 1) { - frm.set_value('allow_appointments', false); - frm.set_df_property('service_unit_type', 'reqd', 0); - } - else { - frm.set_df_property('service_unit_type', 'reqd', 1); - } - }, - overlap_appointments: function(frm) { - if (frm.doc.overlap_appointments == 0) { - frm.set_value('service_unit_capacity', ''); - } - } -}); diff --git a/erpnext/healthcare/doctype/healthcare_service_unit/healthcare_service_unit.json b/erpnext/healthcare/doctype/healthcare_service_unit/healthcare_service_unit.json deleted file mode 100644 index 8935ec7d3c9..00000000000 --- a/erpnext/healthcare/doctype/healthcare_service_unit/healthcare_service_unit.json +++ /dev/null @@ -1,257 +0,0 @@ -{ - "actions": [], - "allow_import": 1, - "allow_rename": 1, - "autoname": "field:healthcare_service_unit_name", - "beta": 1, - "creation": "2016-09-21 13:48:14.731437", - "description": "Healthcare Service Unit", - "doctype": "DocType", - "document_type": "Setup", - "editable_grid": 1, - "engine": "InnoDB", - "field_order": [ - "healthcare_service_unit_name", - "is_group", - "service_unit_type", - "allow_appointments", - "overlap_appointments", - "service_unit_capacity", - "inpatient_occupancy", - "occupancy_status", - "column_break_9", - "company", - "warehouse", - "tree_details_section", - "parent_healthcare_service_unit", - "lft", - "rgt", - "old_parent" - ], - "fields": [ - { - "fieldname": "healthcare_service_unit_name", - "fieldtype": "Data", - "hide_days": 1, - "hide_seconds": 1, - "in_global_search": 1, - "in_list_view": 1, - "label": "Service Unit", - "reqd": 1, - "unique": 1 - }, - { - "bold": 1, - "fieldname": "parent_healthcare_service_unit", - "fieldtype": "Link", - "hide_days": 1, - "hide_seconds": 1, - "ignore_user_permissions": 1, - "in_list_view": 1, - "label": "Parent Service Unit", - "options": "Healthcare Service Unit" - }, - { - "bold": 1, - "default": "0", - "depends_on": "eval:doc.inpatient_occupancy != 1 && doc.allow_appointments != 1", - "fieldname": "is_group", - "fieldtype": "Check", - "hide_days": 1, - "hide_seconds": 1, - "label": "Is Group" - }, - { - "bold": 1, - "depends_on": "eval:doc.is_group != 1", - "fieldname": "service_unit_type", - "fieldtype": "Link", - "hide_days": 1, - "hide_seconds": 1, - "label": "Service Unit Type", - "options": "Healthcare Service Unit Type" - }, - { - "default": "0", - "depends_on": "eval:doc.is_group != 1 && doc.inpatient_occupancy != 1", - "fetch_from": "service_unit_type.allow_appointments", - "fieldname": "allow_appointments", - "fieldtype": "Check", - "hide_days": 1, - "hide_seconds": 1, - "in_list_view": 1, - "label": "Allow Appointments", - "no_copy": 1, - "read_only": 1 - }, - { - "default": "0", - "depends_on": "eval:doc.is_group != 1 && doc.allow_appointments == 1 && doc.inpatient_occupany != 1", - "fetch_from": "service_unit_type.overlap_appointments", - "fieldname": "overlap_appointments", - "fieldtype": "Check", - "hide_days": 1, - "hide_seconds": 1, - "label": "Allow Overlap", - "no_copy": 1, - "read_only": 1 - }, - { - "bold": 1, - "default": "0", - "depends_on": "eval:doc.allow_appointments != 1 && doc.is_group != 1", - "fetch_from": "service_unit_type.inpatient_occupancy", - "fieldname": "inpatient_occupancy", - "fieldtype": "Check", - "hide_days": 1, - "hide_seconds": 1, - "in_list_view": 1, - "label": "Inpatient Occupancy", - "no_copy": 1, - "read_only": 1, - "search_index": 1 - }, - { - "depends_on": "eval:doc.inpatient_occupancy == 1", - "fieldname": "occupancy_status", - "fieldtype": "Select", - "hide_days": 1, - "hide_seconds": 1, - "label": "Occupancy Status", - "no_copy": 1, - "options": "Vacant\nOccupied", - "read_only": 1 - }, - { - "fieldname": "column_break_9", - "fieldtype": "Column Break", - "hide_days": 1, - "hide_seconds": 1 - }, - { - "bold": 1, - "depends_on": "eval:doc.is_group != 1", - "fieldname": "warehouse", - "fieldtype": "Link", - "hide_days": 1, - "hide_seconds": 1, - "label": "Warehouse", - "no_copy": 1, - "options": "Warehouse" - }, - { - "fieldname": "company", - "fieldtype": "Link", - "hide_days": 1, - "hide_seconds": 1, - "ignore_user_permissions": 1, - "in_list_view": 1, - "in_standard_filter": 1, - "label": "Company", - "options": "Company", - "remember_last_selected_value": 1, - "reqd": 1, - "search_index": 1 - }, - { - "fieldname": "lft", - "fieldtype": "Int", - "hidden": 1, - "hide_days": 1, - "hide_seconds": 1, - "label": "lft", - "no_copy": 1, - "print_hide": 1, - "search_index": 1 - }, - { - "fieldname": "rgt", - "fieldtype": "Int", - "hidden": 1, - "hide_days": 1, - "hide_seconds": 1, - "label": "rgt", - "no_copy": 1, - "print_hide": 1, - "search_index": 1 - }, - { - "fieldname": "old_parent", - "fieldtype": "Link", - "hidden": 1, - "hide_days": 1, - "hide_seconds": 1, - "ignore_user_permissions": 1, - "label": "Old Parent", - "no_copy": 1, - "options": "Healthcare Service Unit", - "print_hide": 1, - "report_hide": 1 - }, - { - "collapsible": 1, - "fieldname": "tree_details_section", - "fieldtype": "Section Break", - "hide_days": 1, - "hide_seconds": 1, - "label": "Tree Details" - }, - { - "depends_on": "eval:doc.overlap_appointments == 1", - "fieldname": "service_unit_capacity", - "fieldtype": "Int", - "label": "Service Unit Capacity", - "mandatory_depends_on": "eval:doc.overlap_appointments == 1", - "non_negative": 1 - } - ], - "is_tree": 1, - "links": [], - "modified": "2021-08-19 14:09:11.643464", - "modified_by": "Administrator", - "module": "Healthcare", - "name": "Healthcare Service Unit", - "nsm_parent_field": "parent_healthcare_service_unit", - "owner": "Administrator", - "permissions": [ - { - "email": 1, - "export": 1, - "print": 1, - "read": 1, - "report": 1, - "role": "Nursing User", - "share": 1 - }, - { - "create": 1, - "delete": 1, - "email": 1, - "export": 1, - "print": 1, - "read": 1, - "report": 1, - "role": "Healthcare Administrator", - "share": 1, - "write": 1 - }, - { - "create": 1, - "email": 1, - "export": 1, - "print": 1, - "read": 1, - "report": 1, - "role": "Physician", - "share": 1, - "write": 1 - } - ], - "quick_entry": 1, - "restrict_to_domain": "Healthcare", - "search_fields": "healthcare_service_unit_name", - "sort_field": "modified", - "sort_order": "DESC", - "title_field": "healthcare_service_unit_name", - "track_changes": 1 -} \ No newline at end of file diff --git a/erpnext/healthcare/doctype/healthcare_service_unit/healthcare_service_unit.py b/erpnext/healthcare/doctype/healthcare_service_unit/healthcare_service_unit.py deleted file mode 100644 index 550b9fbff27..00000000000 --- a/erpnext/healthcare/doctype/healthcare_service_unit/healthcare_service_unit.py +++ /dev/null @@ -1,115 +0,0 @@ -# -*- coding: utf-8 -*- -# Copyright (c) 2018, Frappe Technologies Pvt. Ltd. and contributors -# For license information, please see license.txt - -from __future__ import unicode_literals - -import json - -import frappe -from frappe import _ -from frappe.utils import cint, cstr -from frappe.utils.nestedset import NestedSet - - -class HealthcareServiceUnit(NestedSet): - nsm_parent_field = 'parent_healthcare_service_unit' - - def validate(self): - self.set_service_unit_properties() - - def autoname(self): - if self.company: - suffix = " - " + frappe.get_cached_value('Company', self.company, 'abbr') - if not self.healthcare_service_unit_name.endswith(suffix): - self.name = self.healthcare_service_unit_name + suffix - else: - self.name = self.healthcare_service_unit_name - - def on_update(self): - super(HealthcareServiceUnit, self).on_update() - self.validate_one_root() - - def set_service_unit_properties(self): - if cint(self.is_group): - self.allow_appointments = False - self.overlap_appointments = False - self.inpatient_occupancy = False - self.service_unit_capacity = 0 - self.occupancy_status = '' - self.service_unit_type = '' - elif self.service_unit_type != '': - service_unit_type = frappe.get_doc('Healthcare Service Unit Type', self.service_unit_type) - self.allow_appointments = service_unit_type.allow_appointments - self.inpatient_occupancy = service_unit_type.inpatient_occupancy - - if self.inpatient_occupancy and self.occupancy_status != '': - self.occupancy_status = 'Vacant' - - if service_unit_type.overlap_appointments: - self.overlap_appointments = True - else: - self.overlap_appointments = False - self.service_unit_capacity = 0 - - if self.overlap_appointments: - if not self.service_unit_capacity: - frappe.throw(_('Please set a valid Service Unit Capacity to enable Overlapping Appointments'), - title=_('Mandatory')) - - -@frappe.whitelist() -def add_multiple_service_units(parent, data): - ''' - parent - parent service unit under which the service units are to be created - data (dict) - company, healthcare_service_unit_name, count, service_unit_type, warehouse, service_unit_capacity - ''' - if not parent or not data: - return - - data = json.loads(data) - company = data.get('company') or \ - frappe.defaults.get_defaults().get('company') or \ - frappe.db.get_single_value('Global Defaults', 'default_company') - - if not data.get('healthcare_service_unit_name') or not company: - frappe.throw(_('Service Unit Name and Company are mandatory to create Healthcare Service Units'), - title=_('Missing Required Fields')) - - count = cint(data.get('count') or 0) - if count <= 0: - frappe.throw(_('Number of Service Units to be created should at least be 1'), - title=_('Invalid Number of Service Units')) - - capacity = cint(data.get('service_unit_capacity') or 1) - - service_unit = { - 'doctype': 'Healthcare Service Unit', - 'parent_healthcare_service_unit': parent, - 'service_unit_type': data.get('service_unit_type') or None, - 'service_unit_capacity': capacity if capacity > 0 else 1, - 'warehouse': data.get('warehouse') or None, - 'company': company - } - - service_unit_name = '{}'.format(data.get('healthcare_service_unit_name').strip(' -')) - - last_suffix = frappe.db.sql("""SELECT - IFNULL(MAX(CAST(SUBSTRING(name FROM %(start)s FOR 4) AS UNSIGNED)), 0) - FROM `tabHealthcare Service Unit` - WHERE name like %(prefix)s AND company=%(company)s""", - {'start': len(service_unit_name)+2, 'prefix': '{}-%'.format(service_unit_name), 'company': company}, - as_list=1)[0][0] - start_suffix = cint(last_suffix) + 1 - - failed_list = [] - for i in range(start_suffix, count + start_suffix): - # name to be in the form WARD-#### - service_unit['healthcare_service_unit_name'] = '{}-{}'.format(service_unit_name, cstr('%0*d' % (4, i))) - service_unit_doc = frappe.get_doc(service_unit) - try: - service_unit_doc.insert() - except Exception: - failed_list.append(service_unit['healthcare_service_unit_name']) - - return failed_list diff --git a/erpnext/healthcare/doctype/healthcare_service_unit/healthcare_service_unit_tree.js b/erpnext/healthcare/doctype/healthcare_service_unit/healthcare_service_unit_tree.js deleted file mode 100644 index ea3fea6b7a5..00000000000 --- a/erpnext/healthcare/doctype/healthcare_service_unit/healthcare_service_unit_tree.js +++ /dev/null @@ -1,185 +0,0 @@ -frappe.provide("frappe.treeview_settings"); - -frappe.treeview_settings['Healthcare Service Unit'] = { - breadcrumbs: 'Healthcare Service Unit', - title: __('Service Unit Tree'), - get_tree_root: false, - get_tree_nodes: 'erpnext.healthcare.utils.get_children', - filters: [{ - fieldname: 'company', - fieldtype: 'Select', - options: erpnext.utils.get_tree_options('company'), - label: __('Company'), - default: erpnext.utils.get_tree_default('company') - }], - fields: [ - { - fieldtype: 'Data', fieldname: 'healthcare_service_unit_name', label: __('New Service Unit Name'), - reqd: true - }, - { - fieldtype: 'Check', fieldname: 'is_group', label: __('Is Group'), - description: __("Child nodes can be only created under 'Group' type nodes") - }, - { - fieldtype: 'Link', fieldname: 'service_unit_type', label: __('Service Unit Type'), - options: 'Healthcare Service Unit Type', description: __('Type of the new Service Unit'), - depends_on: 'eval:!doc.is_group', default: '', - onchange: () => { - if (cur_dialog) { - if (cur_dialog.fields_dict.service_unit_type.value) { - frappe.db.get_value('Healthcare Service Unit Type', - cur_dialog.fields_dict.service_unit_type.value, 'overlap_appointments') - .then(r => { - if (r.message.overlap_appointments) { - cur_dialog.set_df_property('service_unit_capacity', 'hidden', false); - cur_dialog.set_df_property('service_unit_capacity', 'reqd', true); - } else { - cur_dialog.set_df_property('service_unit_capacity', 'hidden', true); - cur_dialog.set_df_property('service_unit_capacity', 'reqd', false); - } - }); - } else { - cur_dialog.set_df_property('service_unit_capacity', 'hidden', true); - cur_dialog.set_df_property('service_unit_capacity', 'reqd', false); - } - } - } - }, - { - fieldtype: 'Int', fieldname: 'service_unit_capacity', label: __('Service Unit Capacity'), - description: __('Sets the number of concurrent appointments allowed'), reqd: false, - depends_on: "eval:!doc.is_group && doc.service_unit_type != ''", hidden: true - }, - { - fieldtype: 'Link', fieldname: 'warehouse', label: __('Warehouse'), options: 'Warehouse', - description: __('Optional, if you want to manage stock separately for this Service Unit'), - depends_on: 'eval:!doc.is_group' - }, - { - fieldtype: 'Link', fieldname: 'company', label: __('Company'), options: 'Company', reqd: true, - default: () => { - return cur_page.page.page.fields_dict.company.value; - } - } - ], - ignore_fields: ['parent_healthcare_service_unit'], - onrender: function (node) { - if (node.data.occupied_of_available !== undefined) { - $("" - + ' ' + node.data.occupied_of_available - + '').insertBefore(node.$ul); - } - if (node.data && node.data.inpatient_occupancy !== undefined) { - if (node.data.inpatient_occupancy == 1) { - if (node.data.occupancy_status == 'Occupied') { - $("" - + ' ' + node.data.occupancy_status - + '').insertBefore(node.$ul); - } - if (node.data.occupancy_status == 'Vacant') { - $("" - + ' ' + node.data.occupancy_status - + '').insertBefore(node.$ul); - } - } - } - }, - post_render: function (treeview) { - frappe.treeview_settings['Healthcare Service Unit'].treeview = {}; - $.extend(frappe.treeview_settings['Healthcare Service Unit'].treeview, treeview); - }, - toolbar: [ - { - label: __('Add Multiple'), - condition: function (node) { - return node.expandable; - }, - click: function (node) { - const dialog = new frappe.ui.Dialog({ - title: __('Add Multiple Service Units'), - fields: [ - { - fieldtype: 'Data', fieldname: 'healthcare_service_unit_name', label: __('Service Unit Name'), - reqd: true, description: __("Will be serially suffixed to maintain uniquness. Example: 'Ward' will be named as 'Ward-####'"), - }, - { - fieldtype: 'Int', fieldname: 'count', label: __('Number of Service Units'), - reqd: true - }, - { - fieldtype: 'Link', fieldname: 'service_unit_type', label: __('Service Unit Type'), - options: 'Healthcare Service Unit Type', description: __('Type of the new Service Unit'), - depends_on: 'eval:!doc.is_group', default: '', reqd: true, - onchange: () => { - if (cur_dialog) { - if (cur_dialog.fields_dict.service_unit_type.value) { - frappe.db.get_value('Healthcare Service Unit Type', - cur_dialog.fields_dict.service_unit_type.value, 'overlap_appointments') - .then(r => { - if (r.message.overlap_appointments) { - cur_dialog.set_df_property('service_unit_capacity', 'hidden', false); - cur_dialog.set_df_property('service_unit_capacity', 'reqd', true); - } else { - cur_dialog.set_df_property('service_unit_capacity', 'hidden', true); - cur_dialog.set_df_property('service_unit_capacity', 'reqd', false); - } - }); - } else { - cur_dialog.set_df_property('service_unit_capacity', 'hidden', true); - cur_dialog.set_df_property('service_unit_capacity', 'reqd', false); - } - } - } - }, - { - fieldtype: 'Int', fieldname: 'service_unit_capacity', label: __('Service Unit Capacity'), - description: __('Sets the number of concurrent appointments allowed'), reqd: false, - depends_on: "eval:!doc.is_group && doc.service_unit_type != ''", hidden: true - }, - { - fieldtype: 'Link', fieldname: 'warehouse', label: __('Warehouse'), options: 'Warehouse', - description: __('Optional, if you want to manage stock separately for this Service Unit'), - }, - { - fieldtype: 'Link', fieldname: 'company', label: __('Company'), options: 'Company', reqd: true, - default: () => { - return cur_page.page.page.fields_dict.company.get_value(); - } - } - ], - primary_action: () => { - dialog.hide(); - let vals = dialog.get_values(); - if (!vals) return; - - return frappe.call({ - method: 'erpnext.healthcare.doctype.healthcare_service_unit.healthcare_service_unit.add_multiple_service_units', - args: { - parent: node.data.value, - data: vals - }, - callback: function (r) { - if (!r.exc && r.message) { - frappe.treeview_settings['Healthcare Service Unit'].treeview.tree.load_children(node, true); - - frappe.show_alert({ - message: __('{0} Service Units created', [vals.count - r.message.length]), - indicator: 'green' - }); - } else { - frappe.msgprint(__('Could not create Service Units')); - } - }, - freeze: true, - freeze_message: __('Creating {0} Service Units', [vals.count]) - }); - }, - primary_action_label: __('Create') - }); - dialog.show(); - } - } - ], - extend_toolbar: true -}; diff --git a/erpnext/healthcare/doctype/healthcare_service_unit/test_healthcare_service_unit.py b/erpnext/healthcare/doctype/healthcare_service_unit/test_healthcare_service_unit.py deleted file mode 100644 index 84197e56c56..00000000000 --- a/erpnext/healthcare/doctype/healthcare_service_unit/test_healthcare_service_unit.py +++ /dev/null @@ -1,10 +0,0 @@ -# -*- coding: utf-8 -*- -# Copyright (c) 2018, Frappe Technologies Pvt. Ltd. and Contributors -# See license.txt -from __future__ import unicode_literals - -import unittest - - -class TestHealthcareServiceUnit(unittest.TestCase): - pass diff --git a/erpnext/healthcare/doctype/healthcare_service_unit_type/healthcare_service_unit_type.js b/erpnext/healthcare/doctype/healthcare_service_unit_type/healthcare_service_unit_type.js deleted file mode 100644 index ecf4aa1a4bf..00000000000 --- a/erpnext/healthcare/doctype/healthcare_service_unit_type/healthcare_service_unit_type.js +++ /dev/null @@ -1,86 +0,0 @@ -// Copyright (c) 2018, Frappe Technologies Pvt. Ltd. and contributors -// For license information, please see license.txt - -frappe.ui.form.on('Healthcare Service Unit Type', { - refresh: function(frm) { - frm.set_df_property('item_code', 'read_only', frm.doc.__islocal ? 0 : 1); - if (!frm.doc.__islocal && frm.doc.is_billable) { - frm.add_custom_button(__('Change Item Code'), function() { - change_item_code(cur_frm, frm.doc); - }); - } - }, - - service_unit_type: function(frm) { - set_item_details(frm); - - if (!frm.doc.__islocal) { - frm.doc.change_in_item = 1; - } - }, - - is_billable: function(frm) { - set_item_details(frm); - }, - - rate: function(frm) { - if (!frm.doc.__islocal) { - frm.doc.change_in_item = 1; - } - }, - item_group: function(frm) { - if (!frm.doc.__islocal) { - frm.doc.change_in_item = 1; - } - }, - description: function(frm) { - if (!frm.doc.__islocal) { - frm.doc.change_in_item = 1; - } - } -}); - -let set_item_details = function(frm) { - if (frm.doc.service_unit_type && frm.doc.is_billable) { - if (!frm.doc.item_code) - frm.set_value('item_code', frm.doc.service_unit_type); - if (!frm.doc.description) - frm.set_value('description', frm.doc.service_unit_type); - if (!frm.doc.item_group) - frm.set_value('item_group', 'Services'); - } -}; - -let change_item_code = function(frm, doc) { - let d = new frappe.ui.Dialog({ - title: __('Change Item Code'), - fields: [ - { - 'fieldtype': 'Data', - 'label': 'Item Code', - 'fieldname': 'item_code', - 'default': doc.item_code, - reqd: 1, - } - ], - primary_action: function() { - let values = d.get_values(); - if (values) { - frappe.call({ - "method": "erpnext.healthcare.doctype.healthcare_service_unit_type.healthcare_service_unit_type.change_item_code", - "args": { item: doc.item, item_code: values['item_code'], doc_name: doc.name }, - callback: function() { - frm.reload_doc(); - } - }); - } - d.hide(); - }, - primary_action_label: __("Change Template Code") - }); - - d.show(); - d.set_values({ - 'Item Code': frm.doc.item_code - }); -}; diff --git a/erpnext/healthcare/doctype/healthcare_service_unit_type/healthcare_service_unit_type.json b/erpnext/healthcare/doctype/healthcare_service_unit_type/healthcare_service_unit_type.json deleted file mode 100644 index 9c81c65f6b8..00000000000 --- a/erpnext/healthcare/doctype/healthcare_service_unit_type/healthcare_service_unit_type.json +++ /dev/null @@ -1,196 +0,0 @@ -{ - "actions": [], - "allow_import": 1, - "allow_rename": 1, - "autoname": "field:service_unit_type", - "creation": "2018-07-11 16:47:51.414675", - "doctype": "DocType", - "editable_grid": 1, - "engine": "InnoDB", - "field_order": [ - "disabled", - "service_unit_type", - "allow_appointments", - "overlap_appointments", - "inpatient_occupancy", - "is_billable", - "item_details", - "item", - "item_code", - "item_group", - "uom", - "no_of_hours", - "column_break_11", - "rate", - "description", - "change_in_item" - ], - "fields": [ - { - "fieldname": "service_unit_type", - "fieldtype": "Data", - "hide_days": 1, - "hide_seconds": 1, - "in_list_view": 1, - "label": "Service Unit Type", - "no_copy": 1, - "reqd": 1, - "unique": 1 - }, - { - "bold": 1, - "default": "0", - "depends_on": "eval:doc.inpatient_occupancy != 1", - "fieldname": "allow_appointments", - "fieldtype": "Check", - "hide_days": 1, - "hide_seconds": 1, - "label": "Allow Appointments" - }, - { - "bold": 1, - "default": "0", - "depends_on": "eval:doc.allow_appointments == 1 && doc.inpatient_occupany != 1", - "fieldname": "overlap_appointments", - "fieldtype": "Check", - "hide_days": 1, - "hide_seconds": 1, - "label": "Allow Overlap" - }, - { - "bold": 1, - "default": "0", - "depends_on": "eval:doc.allow_appointments != 1", - "fieldname": "inpatient_occupancy", - "fieldtype": "Check", - "hide_days": 1, - "hide_seconds": 1, - "label": "Inpatient Occupancy" - }, - { - "bold": 1, - "default": "0", - "depends_on": "eval:doc.inpatient_occupancy == 1 && doc.allow_appointments != 1", - "fieldname": "is_billable", - "fieldtype": "Check", - "hide_days": 1, - "hide_seconds": 1, - "label": "Is Billable" - }, - { - "depends_on": "is_billable", - "fieldname": "item_details", - "fieldtype": "Section Break", - "hide_days": 1, - "hide_seconds": 1, - "label": "Item Details" - }, - { - "fieldname": "item", - "fieldtype": "Link", - "hide_days": 1, - "hide_seconds": 1, - "label": "Item", - "no_copy": 1, - "options": "Item", - "read_only": 1 - }, - { - "fieldname": "item_code", - "fieldtype": "Data", - "hide_days": 1, - "hide_seconds": 1, - "label": "Item Code", - "mandatory_depends_on": "eval: doc.is_billable == 1", - "no_copy": 1 - }, - { - "fieldname": "item_group", - "fieldtype": "Link", - "hide_days": 1, - "hide_seconds": 1, - "label": "Item Group", - "mandatory_depends_on": "eval: doc.is_billable == 1", - "options": "Item Group" - }, - { - "fieldname": "uom", - "fieldtype": "Link", - "hide_days": 1, - "hide_seconds": 1, - "label": "UOM", - "mandatory_depends_on": "eval: doc.is_billable == 1", - "options": "UOM" - }, - { - "fieldname": "no_of_hours", - "fieldtype": "Int", - "hide_days": 1, - "hide_seconds": 1, - "label": "UOM Conversion in Hours", - "mandatory_depends_on": "eval: doc.is_billable == 1" - }, - { - "fieldname": "column_break_11", - "fieldtype": "Column Break", - "hide_days": 1, - "hide_seconds": 1 - }, - { - "fieldname": "rate", - "fieldtype": "Currency", - "hide_days": 1, - "hide_seconds": 1, - "label": "Rate / UOM" - }, - { - "default": "0", - "fieldname": "disabled", - "fieldtype": "Check", - "hide_days": 1, - "hide_seconds": 1, - "label": "Disabled", - "no_copy": 1 - }, - { - "fieldname": "description", - "fieldtype": "Small Text", - "hide_days": 1, - "hide_seconds": 1, - "label": "Description" - }, - { - "default": "0", - "fieldname": "change_in_item", - "fieldtype": "Check", - "hidden": 1, - "hide_days": 1, - "hide_seconds": 1, - "label": "Change in Item" - } - ], - "links": [], - "modified": "2021-08-19 17:52:30.266667", - "modified_by": "Administrator", - "module": "Healthcare", - "name": "Healthcare Service Unit Type", - "owner": "Administrator", - "permissions": [ - { - "create": 1, - "delete": 1, - "email": 1, - "export": 1, - "print": 1, - "read": 1, - "report": 1, - "role": "Healthcare Administrator", - "share": 1, - "write": 1 - } - ], - "restrict_to_domain": "Healthcare", - "sort_field": "modified", - "sort_order": "DESC", - "title_field": "service_unit_type" -} \ No newline at end of file diff --git a/erpnext/healthcare/doctype/healthcare_service_unit_type/healthcare_service_unit_type.py b/erpnext/healthcare/doctype/healthcare_service_unit_type/healthcare_service_unit_type.py deleted file mode 100644 index 181cb529fc2..00000000000 --- a/erpnext/healthcare/doctype/healthcare_service_unit_type/healthcare_service_unit_type.py +++ /dev/null @@ -1,136 +0,0 @@ -# -*- coding: utf-8 -*- -# Copyright (c) 2018, Frappe Technologies Pvt. Ltd. and contributors -# For license information, please see license.txt - -from __future__ import unicode_literals - -import frappe -from frappe import _ -from frappe.model.document import Document -from frappe.model.rename_doc import rename_doc - - -class HealthcareServiceUnitType(Document): - def validate(self): - if self.allow_appointments and self.inpatient_occupancy: - frappe.msgprint( - _('Healthcare Service Unit Type cannot have both {0} and {1}').format( - frappe.bold('Allow Appointments'), frappe.bold('Inpatient Occupancy')), - raise_exception=1, title=_('Validation Error'), indicator='red' - ) - elif not self.allow_appointments and not self.inpatient_occupancy: - frappe.msgprint( - _('Healthcare Service Unit Type must allow atleast one among {0} and {1}').format( - frappe.bold('Allow Appointments'), frappe.bold('Inpatient Occupancy')), - raise_exception=1, title=_('Validation Error'), indicator='red' - ) - - if not self.allow_appointments: - self.overlap_appointments = 0 - - if self.is_billable: - if self.disabled: - frappe.db.set_value('Item', self.item, 'disabled', 1) - else: - frappe.db.set_value('Item', self.item, 'disabled', 0) - - def after_insert(self): - if self.inpatient_occupancy and self.is_billable: - create_item(self) - - def on_trash(self): - if self.item: - try: - item = self.item - self.db_set('item', '') - frappe.delete_doc('Item', item) - except Exception: - frappe.throw(_('Not permitted. Please disable the Service Unit Type')) - - def on_update(self): - if self.change_in_item and self.is_billable and self.item: - update_item(self) - - item_price = item_price_exists(self) - - if not item_price: - price_list_name = frappe.db.get_value('Price List', {'selling': 1}) - if self.rate: - make_item_price(self.item_code, price_list_name, self.rate) - else: - make_item_price(self.item_code, price_list_name, 0.0) - else: - frappe.db.set_value('Item Price', item_price, 'price_list_rate', self.rate) - - frappe.db.set_value(self.doctype, self.name, 'change_in_item',0) - elif not self.is_billable and self.item: - frappe.db.set_value('Item', self.item, 'disabled', 1) - self.reload() - - -def item_price_exists(doc): - item_price = frappe.db.exists({'doctype': 'Item Price', 'item_code': doc.item_code}) - if len(item_price): - return item_price[0][0] - return False - -def create_item(doc): - # insert item - item = frappe.get_doc({ - 'doctype': 'Item', - 'item_code': doc.item_code, - 'item_name': doc.service_unit_type, - 'item_group': doc.item_group, - 'description': doc.description or doc.item_code, - 'is_sales_item': 1, - 'is_service_item': 1, - 'is_purchase_item': 0, - 'is_stock_item': 0, - 'show_in_website': 0, - 'is_pro_applicable': 0, - 'disabled': 0, - 'stock_uom': doc.uom - }).insert(ignore_permissions=True, ignore_mandatory=True) - - # insert item price - # get item price list to insert item price - price_list_name = frappe.db.get_value('Price List', {'selling': 1}) - if doc.rate: - make_item_price(item.name, price_list_name, doc.rate) - item.standard_rate = doc.rate - else: - make_item_price(item.name, price_list_name, 0.0) - item.standard_rate = 0.0 - - item.save(ignore_permissions=True) - - # Set item in the doc - doc.db_set('item', item.name) - -def make_item_price(item, price_list_name, item_price): - frappe.get_doc({ - 'doctype': 'Item Price', - 'price_list': price_list_name, - 'item_code': item, - 'price_list_rate': item_price - }).insert(ignore_permissions=True, ignore_mandatory=True) - -def update_item(doc): - item = frappe.get_doc("Item", doc.item) - if item: - item.update({ - "item_name": doc.service_unit_type, - "item_group": doc.item_group, - "disabled": 0, - "standard_rate": doc.rate, - "description": doc.description - }) - item.db_update() - -@frappe.whitelist() -def change_item_code(item, item_code, doc_name): - if frappe.db.exists({'doctype': 'Item', 'item_code': item_code}): - frappe.throw(_('Item with Item Code {0} already exists').format(item_code)) - else: - rename_doc('Item', item, item_code, ignore_permissions=True) - frappe.db.set_value('Healthcare Service Unit Type', doc_name, 'item_code', item_code) diff --git a/erpnext/healthcare/doctype/healthcare_service_unit_type/healthcare_service_unit_type_dashboard.py b/erpnext/healthcare/doctype/healthcare_service_unit_type/healthcare_service_unit_type_dashboard.py deleted file mode 100644 index 7421ec3b89c..00000000000 --- a/erpnext/healthcare/doctype/healthcare_service_unit_type/healthcare_service_unit_type_dashboard.py +++ /dev/null @@ -1,15 +0,0 @@ -from __future__ import unicode_literals - -from frappe import _ - - -def get_data(): - return { - 'fieldname': 'service_unit_type', - 'transactions': [ - { - 'label': _('Healthcare Service Units'), - 'items': ['Healthcare Service Unit'] - }, - ] - } diff --git a/erpnext/healthcare/doctype/healthcare_service_unit_type/test_healthcare_service_unit_type.py b/erpnext/healthcare/doctype/healthcare_service_unit_type/test_healthcare_service_unit_type.py deleted file mode 100644 index 839e1d6a4db..00000000000 --- a/erpnext/healthcare/doctype/healthcare_service_unit_type/test_healthcare_service_unit_type.py +++ /dev/null @@ -1,36 +0,0 @@ -# -*- coding: utf-8 -*- -# Copyright (c) 2018, Frappe Technologies Pvt. Ltd. and Contributors -# See license.txt -from __future__ import unicode_literals - -import unittest - -import frappe - - -class TestHealthcareServiceUnitType(unittest.TestCase): - def test_item_creation(self): - unit_type = get_unit_type() - self.assertTrue(frappe.db.exists('Item', unit_type.item)) - - # check item disabled - unit_type.disabled = 1 - unit_type.save() - self.assertEqual(frappe.db.get_value('Item', unit_type.item, 'disabled'), 1) - - -def get_unit_type(): - if frappe.db.exists('Healthcare Service Unit Type', 'Inpatient Rooms'): - return frappe.get_doc('Healthcare Service Unit Type', 'Inpatient Rooms') - - unit_type = frappe.new_doc('Healthcare Service Unit Type') - unit_type.service_unit_type = 'Inpatient Rooms' - unit_type.inpatient_occupancy = 1 - unit_type.is_billable = 1 - unit_type.item_code = 'Inpatient Rooms' - unit_type.item_group = 'Services' - unit_type.uom = 'Hour' - unit_type.no_of_hours = 1 - unit_type.rate = 4000 - unit_type.save() - return unit_type diff --git a/erpnext/healthcare/doctype/healthcare_settings/healthcare_settings.js b/erpnext/healthcare/doctype/healthcare_settings/healthcare_settings.js deleted file mode 100644 index cf2276fc07c..00000000000 --- a/erpnext/healthcare/doctype/healthcare_settings/healthcare_settings.js +++ /dev/null @@ -1,75 +0,0 @@ -// Copyright (c) 2017, Frappe Technologies Pvt. Ltd. and contributors -// For license information, please see license.txt - -frappe.ui.form.on('Healthcare Settings', { - setup: function(frm) { - frm.set_query('account', 'receivable_account', function(doc, cdt, cdn) { - var d = locals[cdt][cdn]; - return { - filters: { - 'account_type': 'Receivable', - 'company': d.company, - 'is_group': 0 - } - }; - }); - frm.set_query('account', 'income_account', function(doc, cdt, cdn) { - var d = locals[cdt][cdn]; - return { - filters: { - 'root_type': 'Income', - 'company': d.company, - 'is_group': 0 - } - }; - }); - set_query_service_item(frm, 'inpatient_visit_charge_item'); - set_query_service_item(frm, 'op_consulting_charge_item'); - set_query_service_item(frm, 'clinical_procedure_consumable_item'); - } -}); - -var set_query_service_item = function(frm, service_item_field) { - frm.set_query(service_item_field, function() { - return { - filters: { - 'is_sales_item': 1, - 'is_stock_item': 0 - } - }; - }); -}; - -frappe.tour['Healthcare Settings'] = [ - { - fieldname: 'link_customer_to_patient', - title: __('Link Customer to Patient'), - description: __('If checked, a customer will be created for every Patient. Patient Invoices will be created against this Customer. You can also select existing Customer while creating a Patient. This field is checked by default.') - }, - { - fieldname: 'collect_registration_fee', - title: __('Collect Registration Fee'), - description: __('If your Healthcare facility bills registrations of Patients, you can check this and set the Registration Fee in the field below. Checking this will create new Patients with a Disabled status by default and will only be enabled after invoicing the Registration Fee.') - }, - { - fieldname: 'automate_appointment_invoicing', - title: __('Automate Appointment Invoicing'), - description: __('Checking this will automatically create a Sales Invoice whenever an appointment is booked for a Patient.') - }, - { - fieldname: 'inpatient_visit_charge_item', - title: __('Healthcare Service Items'), - description: __('You can create a service item for Inpatient Visit Charge and set it here. Similarly, you can set up other Healthcare Service Items for billing in this section. Click ') + "here" + __(' to know more') - }, - { - fieldname: 'income_account', - title: __('Set up default Accounts for the Healthcare Facility'), - description: __('If you wish to override default accounts settings and configure the Income and Receivable accounts for Healthcare, you can do so here.') - - }, - { - fieldname: 'send_registration_msg', - title: __('Out Patient SMS alerts'), - description: __('If you want to send SMS alert on Patient Registration, you can enable this option. Similary, you can set up Out Patient SMS alerts for other functionalities in this section. Click ') + "here" + __(' to know more') - } -]; diff --git a/erpnext/healthcare/doctype/healthcare_settings/healthcare_settings.json b/erpnext/healthcare/doctype/healthcare_settings/healthcare_settings.json deleted file mode 100644 index ddf1bce4927..00000000000 --- a/erpnext/healthcare/doctype/healthcare_settings/healthcare_settings.json +++ /dev/null @@ -1,351 +0,0 @@ -{ - "actions": [], - "beta": 1, - "creation": "2017-05-09 11:26:22.337760", - "doctype": "DocType", - "editable_grid": 1, - "engine": "InnoDB", - "field_order": [ - "sb_op_settings", - "patient_name_by", - "link_customer_to_patient", - "default_medical_code_standard", - "column_break_9", - "collect_registration_fee", - "registration_fee", - "automate_appointment_invoicing", - "enable_free_follow_ups", - "max_visits", - "valid_days", - "inpatient_settings_section", - "allow_discharge_despite_unbilled_services", - "do_not_bill_inpatient_encounters", - "healthcare_service_items", - "inpatient_visit_charge_item", - "op_consulting_charge_item", - "column_break_13", - "clinical_procedure_consumable_item", - "sb_in_ac", - "income_account", - "receivable_account", - "out_patient_sms_alerts", - "send_registration_msg", - "registration_msg", - "send_appointment_confirmation", - "appointment_confirmation_msg", - "avoid_confirmation", - "column_break_16", - "send_appointment_reminder", - "appointment_reminder_msg", - "remind_before", - "sb_lab_settings", - "create_lab_test_on_si_submit", - "create_sample_collection_for_lab_test", - "column_break_34", - "lab_test_approval_required", - "employee_name_and_designation_in_print", - "custom_signature_in_print", - "laboratory_sms_alerts", - "sms_printed", - "column_break_28", - "sms_emailed" - ], - "fields": [ - { - "fieldname": "sb_op_settings", - "fieldtype": "Section Break", - "label": "Out Patient Settings" - }, - { - "fieldname": "default_medical_code_standard", - "fieldtype": "Link", - "label": "Default Medical Code Standard", - "options": "Medical Code Standard" - }, - { - "fieldname": "column_break_9", - "fieldtype": "Column Break" - }, - { - "default": "0", - "description": "Checking this will create new Patients with a Disabled status by default and will only be enabled after invoicing the Registration Fee.", - "fieldname": "collect_registration_fee", - "fieldtype": "Check", - "label": "Collect Fee for Patient Registration" - }, - { - "depends_on": "collect_registration_fee", - "fieldname": "registration_fee", - "fieldtype": "Currency", - "label": "Registration Fee", - "mandatory_depends_on": "eval:doc.collect_registration_fee == 1", - "options": "Currency" - }, - { - "depends_on": "eval:doc.enable_free_follow_ups == 1", - "description": "Time period (Valid number of days) for free consultations", - "fieldname": "valid_days", - "fieldtype": "Int", - "label": "Valid Number of Days", - "mandatory_depends_on": "eval:doc.enable_free_follow_ups == 1" - }, - { - "collapsible": 1, - "description": "You can configure default Items for billing consultation charges, procedure consumption items and inpatient visits", - "fieldname": "healthcare_service_items", - "fieldtype": "Section Break", - "label": "Default Healthcare Service Items" - }, - { - "fieldname": "inpatient_visit_charge_item", - "fieldtype": "Link", - "label": "Inpatient Visit Charge Item", - "options": "Item" - }, - { - "fieldname": "op_consulting_charge_item", - "fieldtype": "Link", - "label": "Out Patient Consulting Charge Item", - "options": "Item" - }, - { - "fieldname": "column_break_13", - "fieldtype": "Column Break" - }, - { - "fieldname": "clinical_procedure_consumable_item", - "fieldtype": "Link", - "label": "Clinical Procedure Consumable Item", - "options": "Item" - }, - { - "collapsible": 1, - "fieldname": "out_patient_sms_alerts", - "fieldtype": "Section Break", - "label": "Out Patient SMS Alerts" - }, - { - "fieldname": "column_break_16", - "fieldtype": "Column Break" - }, - { - "collapsible": 1, - "fieldname": "sb_in_ac", - "fieldtype": "Section Break", - "label": "Default Accounts" - }, - { - "description": "Default income accounts to be used if not set in Healthcare Practitioner to book Appointment charges.", - "fieldname": "income_account", - "fieldtype": "Table", - "label": "Income Account", - "options": "Party Account" - }, - { - "description": "Default receivable accounts to be used to book Appointment charges.", - "fieldname": "receivable_account", - "fieldtype": "Table", - "label": "Receivable Account", - "options": "Party Account" - }, - { - "collapsible": 1, - "fieldname": "sb_lab_settings", - "fieldtype": "Section Break", - "label": "Laboratory Settings" - }, - { - "fieldname": "column_break_34", - "fieldtype": "Column Break" - }, - { - "default": "1", - "description": "Check this if you want the Name and Designation of the Employee associated with the User who submits the document to be printed in the Lab Test Report.", - "fieldname": "employee_name_and_designation_in_print", - "fieldtype": "Check", - "label": "Employee name and designation in print" - }, - { - "depends_on": "eval:doc.employee_name_and_designation_in_print == '0'\n", - "fieldname": "custom_signature_in_print", - "fieldtype": "Small Text", - "label": "Custom Signature in Print" - }, - { - "collapsible": 1, - "fieldname": "laboratory_sms_alerts", - "fieldtype": "Section Break", - "label": "Laboratory SMS Alerts" - }, - { - "default": "Hello {{doc.patient}}, Your {{doc.lab_test_name}} result is ready with {{doc.company }}. \nThank You, Good day!", - "fieldname": "sms_printed", - "fieldtype": "Small Text", - "ignore_xss_filter": 1, - "label": "Result Printed Message" - }, - { - "fieldname": "column_break_28", - "fieldtype": "Column Break" - }, - { - "default": "Hello {{doc.patient}}, Your {{doc.lab_test_name}} result has been emailed to {{doc.email}}. \n{{doc.company }}. \nThank You, Good day!", - "fieldname": "sms_emailed", - "fieldtype": "Small Text", - "ignore_xss_filter": 1, - "label": "Result Emailed Message" - }, - { - "default": "0", - "description": "Checking this will restrict printing and emailing of Lab Test documents unless they have the status as Approved.", - "fieldname": "lab_test_approval_required", - "fieldtype": "Check", - "label": "Do not print or email Lab Tests without Approval" - }, - { - "default": "1", - "description": "If checked, a customer will be created, mapped to Patient.\nPatient Invoices will be created against this Customer. You can also select existing Customer while creating Patient.", - "fieldname": "link_customer_to_patient", - "fieldtype": "Check", - "label": "Link Customer to Patient" - }, - { - "default": "0", - "description": "Checking this will create Lab Test(s) specified in the Sales Invoice on submission.", - "fieldname": "create_lab_test_on_si_submit", - "fieldtype": "Check", - "label": "Create Lab Test(s) on Sales Invoice Submission" - }, - { - "default": "0", - "description": "Checking this will create a Sample Collection document every time you create a Lab Test", - "fieldname": "create_sample_collection_for_lab_test", - "fieldtype": "Check", - "label": "Create Sample Collection document for Lab Test" - }, - { - "fieldname": "patient_name_by", - "fieldtype": "Select", - "label": "Patient Name By", - "options": "Patient Name\nNaming Series" - }, - { - "default": "0", - "description": "Manage Appointment Invoice submit and cancel automatically for Patient Encounter", - "fieldname": "automate_appointment_invoicing", - "fieldtype": "Check", - "label": "Automate Appointment Invoicing" - }, - { - "default": "0", - "fieldname": "send_registration_msg", - "fieldtype": "Check", - "label": "Patient Registration" - }, - { - "default": "Hello {{doc.patient}}, Thank you for registering with {{doc.company}}. Your ID is {{doc.name}} . Please note this ID for future reference. \nThank You!", - "depends_on": "send_registration_msg", - "fieldname": "registration_msg", - "fieldtype": "Small Text", - "ignore_xss_filter": 1, - "label": "Registration Message" - }, - { - "default": "0", - "fieldname": "send_appointment_confirmation", - "fieldtype": "Check", - "label": "Appointment Confirmation" - }, - { - "default": "Hello {{doc.patient}}, You have scheduled an appointment with {{doc.practitioner}} on {{doc.appointment_datetime}} at {{doc.company}}.\nThank you, Good day!", - "depends_on": "send_appointment_confirmation", - "fieldname": "appointment_confirmation_msg", - "fieldtype": "Small Text", - "ignore_xss_filter": 1, - "label": "Confirmation Message" - }, - { - "default": "0", - "depends_on": "send_appointment_confirmation", - "description": "Do not confirm if appointment is created for the same day", - "fieldname": "avoid_confirmation", - "fieldtype": "Check", - "label": "Avoid Confirmation" - }, - { - "default": "0", - "fieldname": "send_appointment_reminder", - "fieldtype": "Check", - "label": "Appointment Reminder" - }, - { - "default": "Hello {{doc.patient}}, You have an appointment with {{doc.practitioner}} by {{doc.appointment_datetime}} at {{doc.company}}.\nThank you, Good day!\n", - "depends_on": "send_appointment_reminder", - "fieldname": "appointment_reminder_msg", - "fieldtype": "Small Text", - "ignore_xss_filter": 1, - "label": "Reminder Message" - }, - { - "depends_on": "send_appointment_reminder", - "fieldname": "remind_before", - "fieldtype": "Time", - "label": "Remind Before" - }, - { - "depends_on": "eval:doc.enable_free_follow_ups == 1", - "description": "The number of free follow ups (Patient Encounters in valid days) allowed", - "fieldname": "max_visits", - "fieldtype": "Int", - "label": "Number of Patient Encounters in Valid Days", - "mandatory_depends_on": "eval:doc.enable_free_follow_ups == 1" - }, - { - "default": "0", - "fieldname": "enable_free_follow_ups", - "fieldtype": "Check", - "label": "Enable Free Follow-ups" - }, - { - "fieldname": "inpatient_settings_section", - "fieldtype": "Section Break", - "label": "Inpatient Settings" - }, - { - "default": "0", - "fieldname": "allow_discharge_despite_unbilled_services", - "fieldtype": "Check", - "label": "Allow Discharge Despite Unbilled Healthcare Services" - }, - { - "default": "0", - "fieldname": "do_not_bill_inpatient_encounters", - "fieldtype": "Check", - "label": "Do Not Bill Patient Encounters for Inpatients" - } - ], - "issingle": 1, - "links": [], - "modified": "2021-01-13 09:04:35.877700", - "modified_by": "Administrator", - "module": "Healthcare", - "name": "Healthcare Settings", - "owner": "Administrator", - "permissions": [ - { - "create": 1, - "delete": 1, - "email": 1, - "print": 1, - "read": 1, - "role": "Healthcare Administrator", - "share": 1, - "write": 1 - } - ], - "quick_entry": 1, - "restrict_to_domain": "Healthcare", - "sort_field": "modified", - "sort_order": "DESC", - "track_changes": 1 -} \ No newline at end of file diff --git a/erpnext/healthcare/doctype/healthcare_settings/healthcare_settings.py b/erpnext/healthcare/doctype/healthcare_settings/healthcare_settings.py deleted file mode 100644 index 9ab88817661..00000000000 --- a/erpnext/healthcare/doctype/healthcare_settings/healthcare_settings.py +++ /dev/null @@ -1,93 +0,0 @@ -# -*- coding: utf-8 -*- -# Copyright (c) 2017, Frappe Technologies Pvt. Ltd. and contributors -# For license information, please see license.txt - -from __future__ import unicode_literals - -import json - -import frappe -from frappe import _ -from frappe.core.doctype.sms_settings.sms_settings import send_sms -from frappe.model.document import Document - - -class HealthcareSettings(Document): - def validate(self): - for key in ['collect_registration_fee', 'link_customer_to_patient', 'patient_name_by', - 'lab_test_approval_required', 'create_sample_collection_for_lab_test', 'default_medical_code_standard']: - frappe.db.set_default(key, self.get(key, "")) - - if self.collect_registration_fee: - if self.registration_fee <= 0: - frappe.throw(_('Registration Fee cannot be negative or zero')) - - if self.inpatient_visit_charge_item: - validate_service_item(self.inpatient_visit_charge_item) - if self.op_consulting_charge_item: - validate_service_item(self.op_consulting_charge_item) - if self.clinical_procedure_consumable_item: - validate_service_item(self.clinical_procedure_consumable_item) - - -def validate_service_item(item): - if frappe.db.get_value('Item', item, 'is_stock_item'): - frappe.throw(_('Configure a service Item for {0}').format(item)) - -@frappe.whitelist() -def get_sms_text(doc): - sms_text = {} - doc = frappe.get_doc('Lab Test', doc) - context = {'doc': doc, 'alert': doc, 'comments': None} - - emailed = frappe.db.get_value('Healthcare Settings', None, 'sms_emailed') - sms_text['emailed'] = frappe.render_template(emailed, context) - - printed = frappe.db.get_value('Healthcare Settings', None, 'sms_printed') - sms_text['printed'] = frappe.render_template(printed, context) - - return sms_text - -def send_registration_sms(doc): - if frappe.db.get_single_value('Healthcare Settings', 'send_registration_msg'): - if doc.mobile: - context = {'doc': doc, 'alert': doc, 'comments': None} - if doc.get('_comments'): - context['comments'] = json.loads(doc.get('_comments')) - messages = frappe.db.get_single_value('Healthcare Settings', 'registration_msg') - messages = frappe.render_template(messages, context) - number = [doc.mobile] - send_sms(number,messages) - else: - frappe.msgprint(doc.name + ' has no mobile number to send registration SMS', alert=True) - -def get_receivable_account(company): - receivable_account = get_account(None, 'receivable_account', 'Healthcare Settings', company) - if receivable_account: - return receivable_account - - return frappe.get_cached_value('Company', company, 'default_receivable_account') - -def get_income_account(practitioner, company): - # check income account in Healthcare Practitioner - if practitioner: - income_account = get_account('Healthcare Practitioner', None, practitioner, company) - if income_account: - return income_account - - # else check income account in Healthcare Settings - income_account = get_account(None, 'income_account', 'Healthcare Settings', company) - if income_account: - return income_account - - # else return default income account of company - return frappe.get_cached_value('Company', company, 'default_income_account') - -def get_account(parent_type, parent_field, parent, company): - if parent_type: - return frappe.db.get_value('Party Account', - {'parenttype': parent_type, 'parent': parent, 'company': company}, 'account') - - if parent_field: - return frappe.db.get_value('Party Account', - {'parentfield': parent_field, 'parent': parent, 'company': company}, 'account') diff --git a/erpnext/healthcare/doctype/healthcare_settings/test_healthcare_settings.py b/erpnext/healthcare/doctype/healthcare_settings/test_healthcare_settings.py deleted file mode 100644 index af2f2b4c4f5..00000000000 --- a/erpnext/healthcare/doctype/healthcare_settings/test_healthcare_settings.py +++ /dev/null @@ -1,10 +0,0 @@ -# -*- coding: utf-8 -*- -# Copyright (c) 2017, Frappe Technologies Pvt. Ltd. and Contributors -# See license.txt -from __future__ import unicode_literals - -import unittest - - -class TestHealthcareSettings(unittest.TestCase): - pass diff --git a/erpnext/healthcare/doctype/inpatient_medication_entry/inpatient_medication_entry.js b/erpnext/healthcare/doctype/inpatient_medication_entry/inpatient_medication_entry.js deleted file mode 100644 index a7b06b1718b..00000000000 --- a/erpnext/healthcare/doctype/inpatient_medication_entry/inpatient_medication_entry.js +++ /dev/null @@ -1,74 +0,0 @@ -// Copyright (c) 2020, Frappe Technologies Pvt. Ltd. and contributors -// For license information, please see license.txt - -frappe.ui.form.on('Inpatient Medication Entry', { - refresh: function(frm) { - // Ignore cancellation of doctype on cancel all - frm.ignore_doctypes_on_cancel_all = ['Stock Entry']; - frm.fields_dict['medication_orders'].grid.wrapper.find('.grid-add-row').hide(); - - frm.set_query('item_code', () => { - return { - filters: { - is_stock_item: 1 - } - }; - }); - - frm.set_query('drug_code', 'medication_orders', () => { - return { - filters: { - is_stock_item: 1 - } - }; - }); - - frm.set_query('warehouse', () => { - return { - filters: { - company: frm.doc.company - } - }; - }); - - if (frm.doc.__islocal || frm.doc.docstatus !== 0 || !frm.doc.update_stock) - return; - - frm.add_custom_button(__('Make Stock Entry'), function() { - frappe.call({ - method: 'erpnext.healthcare.doctype.inpatient_medication_entry.inpatient_medication_entry.make_difference_stock_entry', - args: { docname: frm.doc.name }, - freeze: true, - callback: function(r) { - if (r.message) { - var doclist = frappe.model.sync(r.message); - frappe.set_route('Form', doclist[0].doctype, doclist[0].name); - } else { - frappe.msgprint({ - title: __('No Drug Shortage'), - message: __('All the drugs are available with sufficient qty to process this Inpatient Medication Entry.'), - indicator: 'green' - }); - } - } - }); - }); - }, - - patient: function(frm) { - if (frm.doc.patient) - frm.set_value('service_unit', ''); - }, - - get_medication_orders: function(frm) { - frappe.call({ - method: 'get_medication_orders', - doc: frm.doc, - freeze: true, - freeze_message: __('Fetching Pending Medication Orders'), - callback: function() { - refresh_field('medication_orders'); - } - }); - } -}); diff --git a/erpnext/healthcare/doctype/inpatient_medication_entry/inpatient_medication_entry.json b/erpnext/healthcare/doctype/inpatient_medication_entry/inpatient_medication_entry.json deleted file mode 100644 index b1a6ee4ed14..00000000000 --- a/erpnext/healthcare/doctype/inpatient_medication_entry/inpatient_medication_entry.json +++ /dev/null @@ -1,204 +0,0 @@ -{ - "actions": [], - "autoname": "naming_series:", - "creation": "2020-09-25 14:13:20.111906", - "doctype": "DocType", - "editable_grid": 1, - "engine": "InnoDB", - "field_order": [ - "naming_series", - "company", - "column_break_3", - "posting_date", - "status", - "filters_section", - "item_code", - "assigned_to_practitioner", - "patient", - "practitioner", - "service_unit", - "column_break_11", - "from_date", - "to_date", - "from_time", - "to_time", - "select_medication_orders_section", - "get_medication_orders", - "medication_orders", - "section_break_18", - "update_stock", - "warehouse", - "amended_from" - ], - "fields": [ - { - "fieldname": "naming_series", - "fieldtype": "Select", - "label": "Naming Series", - "options": "HLC-IME-.YYYY.-" - }, - { - "fieldname": "company", - "fieldtype": "Link", - "in_list_view": 1, - "in_standard_filter": 1, - "label": "Company", - "options": "Company", - "reqd": 1 - }, - { - "fieldname": "column_break_3", - "fieldtype": "Column Break" - }, - { - "fieldname": "posting_date", - "fieldtype": "Date", - "in_list_view": 1, - "in_standard_filter": 1, - "label": "Posting Date", - "reqd": 1 - }, - { - "fieldname": "status", - "fieldtype": "Select", - "label": "Status", - "options": "\nDraft\nSubmitted\nPending\nIn Process\nCompleted\nCancelled", - "read_only": 1 - }, - { - "collapsible": 1, - "collapsible_depends_on": "eval: doc.__islocal", - "fieldname": "filters_section", - "fieldtype": "Section Break", - "label": "Filters" - }, - { - "fieldname": "item_code", - "fieldtype": "Link", - "label": "Item Code (Drug)", - "options": "Item" - }, - { - "depends_on": "update_stock", - "description": "Warehouse from where medication stock should be consumed", - "fieldname": "warehouse", - "fieldtype": "Link", - "label": "Medication Warehouse", - "mandatory_depends_on": "update_stock", - "options": "Warehouse" - }, - { - "fieldname": "patient", - "fieldtype": "Link", - "label": "Patient", - "options": "Patient" - }, - { - "depends_on": "eval:!doc.patient", - "fieldname": "service_unit", - "fieldtype": "Link", - "label": "Healthcare Service Unit", - "options": "Healthcare Service Unit" - }, - { - "fieldname": "column_break_11", - "fieldtype": "Column Break" - }, - { - "fieldname": "from_date", - "fieldtype": "Date", - "label": "From Date" - }, - { - "fieldname": "to_date", - "fieldtype": "Date", - "label": "To Date" - }, - { - "fieldname": "amended_from", - "fieldtype": "Link", - "label": "Amended From", - "no_copy": 1, - "options": "Inpatient Medication Entry", - "print_hide": 1, - "read_only": 1 - }, - { - "fieldname": "practitioner", - "fieldtype": "Link", - "label": "Healthcare Practitioner", - "options": "Healthcare Practitioner" - }, - { - "fieldname": "select_medication_orders_section", - "fieldtype": "Section Break", - "label": "Medication Orders" - }, - { - "fieldname": "medication_orders", - "fieldtype": "Table", - "label": "Inpatient Medication Orders", - "options": "Inpatient Medication Entry Detail", - "reqd": 1 - }, - { - "depends_on": "eval:doc.docstatus!==1", - "fieldname": "get_medication_orders", - "fieldtype": "Button", - "label": "Get Pending Medication Orders", - "print_hide": 1 - }, - { - "fieldname": "assigned_to_practitioner", - "fieldtype": "Link", - "label": "Assigned To", - "options": "User" - }, - { - "fieldname": "section_break_18", - "fieldtype": "Section Break", - "label": "Stock Details" - }, - { - "default": "1", - "fieldname": "update_stock", - "fieldtype": "Check", - "label": "Update Stock" - }, - { - "fieldname": "from_time", - "fieldtype": "Time", - "label": "From Time" - }, - { - "fieldname": "to_time", - "fieldtype": "Time", - "label": "To Time" - } - ], - "index_web_pages_for_search": 1, - "is_submittable": 1, - "links": [], - "modified": "2021-01-11 12:37:46.749659", - "modified_by": "Administrator", - "module": "Healthcare", - "name": "Inpatient Medication Entry", - "owner": "Administrator", - "permissions": [ - { - "create": 1, - "delete": 1, - "email": 1, - "export": 1, - "print": 1, - "read": 1, - "report": 1, - "role": "System Manager", - "share": 1, - "write": 1 - } - ], - "sort_field": "modified", - "sort_order": "DESC", - "track_changes": 1 -} \ No newline at end of file diff --git a/erpnext/healthcare/doctype/inpatient_medication_entry/inpatient_medication_entry.py b/erpnext/healthcare/doctype/inpatient_medication_entry/inpatient_medication_entry.py deleted file mode 100644 index b28e37a9c31..00000000000 --- a/erpnext/healthcare/doctype/inpatient_medication_entry/inpatient_medication_entry.py +++ /dev/null @@ -1,324 +0,0 @@ -# -*- coding: utf-8 -*- -# Copyright (c) 2020, Frappe Technologies Pvt. Ltd. and contributors -# For license information, please see license.txt - -from __future__ import unicode_literals - -import frappe -from frappe import _ -from frappe.model.document import Document -from frappe.utils import flt, get_link_to_form - -from erpnext.healthcare.doctype.healthcare_settings.healthcare_settings import get_account -from erpnext.stock.utils import get_latest_stock_qty - - -class InpatientMedicationEntry(Document): - def validate(self): - self.validate_medication_orders() - - @frappe.whitelist() - def get_medication_orders(self): - # pull inpatient medication orders based on selected filters - orders = get_pending_medication_orders(self) - - if orders: - self.add_mo_to_table(orders) - return self - else: - self.set('medication_orders', []) - frappe.msgprint(_('No pending medication orders found for selected criteria')) - - def add_mo_to_table(self, orders): - # Add medication orders in the child table - self.set('medication_orders', []) - - for data in orders: - self.append('medication_orders', { - 'patient': data.patient, - 'patient_name': data.patient_name, - 'inpatient_record': data.inpatient_record, - 'service_unit': data.service_unit, - 'datetime': "%s %s" % (data.date, data.time or "00:00:00"), - 'drug_code': data.drug, - 'drug_name': data.drug_name, - 'dosage': data.dosage, - 'dosage_form': data.dosage_form, - 'against_imo': data.parent, - 'against_imoe': data.name - }) - - def on_submit(self): - self.validate_medication_orders() - success_msg = "" - if self.update_stock: - stock_entry = self.process_stock() - success_msg += _('Stock Entry {0} created and ').format( - frappe.bold(get_link_to_form('Stock Entry', stock_entry))) - - self.update_medication_orders() - success_msg += _('Inpatient Medication Orders updated successfully') - frappe.msgprint(success_msg, title=_('Success'), indicator='green') - - def validate_medication_orders(self): - for entry in self.medication_orders: - docstatus, is_completed = frappe.db.get_value('Inpatient Medication Order Entry', entry.against_imoe, - ['docstatus', 'is_completed']) - - if docstatus == 2: - frappe.throw(_('Row {0}: Cannot create Inpatient Medication Entry against cancelled Inpatient Medication Order {1}').format( - entry.idx, get_link_to_form(entry.against_imo))) - - if is_completed: - frappe.throw(_('Row {0}: This Medication Order is already marked as completed').format( - entry.idx)) - - def on_cancel(self): - self.cancel_stock_entries() - self.update_medication_orders(on_cancel=True) - - def process_stock(self): - allow_negative_stock = frappe.db.get_single_value('Stock Settings', 'allow_negative_stock') - if not allow_negative_stock: - self.check_stock_qty() - - return self.make_stock_entry() - - def update_medication_orders(self, on_cancel=False): - orders, order_entry_map = self.get_order_entry_map() - # mark completion status - is_completed = 1 - if on_cancel: - is_completed = 0 - - frappe.db.sql(""" - UPDATE `tabInpatient Medication Order Entry` - SET is_completed = %(is_completed)s - WHERE name IN %(orders)s - """, {'orders': orders, 'is_completed': is_completed}) - - # update status and completed orders count - for order, count in order_entry_map.items(): - medication_order = frappe.get_doc('Inpatient Medication Order', order) - completed_orders = flt(count) - current_value = frappe.db.get_value('Inpatient Medication Order', order, 'completed_orders') - - if on_cancel: - completed_orders = flt(current_value) - flt(count) - else: - completed_orders = flt(current_value) + flt(count) - - medication_order.db_set('completed_orders', completed_orders) - medication_order.set_status() - - def get_order_entry_map(self): - # for marking order completion status - orders = [] - # orders mapped - order_entry_map = dict() - - for entry in self.medication_orders: - orders.append(entry.against_imoe) - parent = entry.against_imo - if not order_entry_map.get(parent): - order_entry_map[parent] = 0 - - order_entry_map[parent] += 1 - - return orders, order_entry_map - - def check_stock_qty(self): - drug_shortage = get_drug_shortage_map(self.medication_orders, self.warehouse) - - if drug_shortage: - message = _('Quantity not available for the following items in warehouse {0}. ').format(frappe.bold(self.warehouse)) - message += _('Please enable Allow Negative Stock in Stock Settings or create Stock Entry to proceed.') - - formatted_item_rows = '' - - for drug, shortage_qty in drug_shortage.items(): - item_link = get_link_to_form('Item', drug) - formatted_item_rows += """ -

{0}{1}
- - - - - {2} -
{0}{1}
- """.format(_('Drug Code'), _('Shortage Qty'), formatted_item_rows) - - frappe.throw(message, title=_('Insufficient Stock'), is_minimizable=True, wide=True) - - def make_stock_entry(self): - stock_entry = frappe.new_doc('Stock Entry') - stock_entry.purpose = 'Material Issue' - stock_entry.set_stock_entry_type() - stock_entry.from_warehouse = self.warehouse - stock_entry.company = self.company - stock_entry.inpatient_medication_entry = self.name - cost_center = frappe.get_cached_value('Company', self.company, 'cost_center') - expense_account = get_account(None, 'expense_account', 'Healthcare Settings', self.company) - - for entry in self.medication_orders: - se_child = stock_entry.append('items') - se_child.item_code = entry.drug_code - se_child.item_name = entry.drug_name - se_child.uom = frappe.db.get_value('Item', entry.drug_code, 'stock_uom') - se_child.stock_uom = se_child.uom - se_child.qty = flt(entry.dosage) - # in stock uom - se_child.conversion_factor = 1 - se_child.cost_center = cost_center - se_child.expense_account = expense_account - # references - se_child.patient = entry.patient - se_child.inpatient_medication_entry_child = entry.name - - stock_entry.submit() - return stock_entry.name - - def cancel_stock_entries(self): - stock_entries = frappe.get_all('Stock Entry', {'inpatient_medication_entry': self.name}) - for entry in stock_entries: - doc = frappe.get_doc('Stock Entry', entry.name) - doc.cancel() - - -def get_pending_medication_orders(entry): - filters, values = get_filters(entry) - to_remove = [] - - data = frappe.db.sql(""" - SELECT - ip.inpatient_record, ip.patient, ip.patient_name, - entry.name, entry.parent, entry.drug, entry.drug_name, - entry.dosage, entry.dosage_form, entry.date, entry.time, entry.instructions - FROM - `tabInpatient Medication Order` ip - INNER JOIN - `tabInpatient Medication Order Entry` entry - ON - ip.name = entry.parent - WHERE - ip.docstatus = 1 and - ip.company = %(company)s and - entry.is_completed = 0 - {0} - ORDER BY - entry.date, entry.time - """.format(filters), values, as_dict=1) - - for doc in data: - inpatient_record = doc.inpatient_record - if inpatient_record: - doc['service_unit'] = get_current_healthcare_service_unit(inpatient_record) - - if entry.service_unit and doc.service_unit != entry.service_unit: - to_remove.append(doc) - - for doc in to_remove: - data.remove(doc) - - return data - - -def get_filters(entry): - filters = '' - values = dict(company=entry.company) - if entry.from_date: - filters += ' and entry.date >= %(from_date)s' - values['from_date'] = entry.from_date - - if entry.to_date: - filters += ' and entry.date <= %(to_date)s' - values['to_date'] = entry.to_date - - if entry.from_time: - filters += ' and entry.time >= %(from_time)s' - values['from_time'] = entry.from_time - - if entry.to_time: - filters += ' and entry.time <= %(to_time)s' - values['to_time'] = entry.to_time - - if entry.patient: - filters += ' and ip.patient = %(patient)s' - values['patient'] = entry.patient - - if entry.practitioner: - filters += ' and ip.practitioner = %(practitioner)s' - values['practitioner'] = entry.practitioner - - if entry.item_code: - filters += ' and entry.drug = %(item_code)s' - values['item_code'] = entry.item_code - - if entry.assigned_to_practitioner: - filters += ' and ip._assign LIKE %(assigned_to)s' - values['assigned_to'] = '%' + entry.assigned_to_practitioner + '%' - - return filters, values - - -def get_current_healthcare_service_unit(inpatient_record): - ip_record = frappe.get_doc('Inpatient Record', inpatient_record) - if ip_record.status in ['Admitted', 'Discharge Scheduled'] and ip_record.inpatient_occupancies: - return ip_record.inpatient_occupancies[-1].service_unit - return - - -def get_drug_shortage_map(medication_orders, warehouse): - """ - Returns a dict like { drug_code: shortage_qty } - """ - drug_requirement = dict() - for d in medication_orders: - if not drug_requirement.get(d.drug_code): - drug_requirement[d.drug_code] = 0 - drug_requirement[d.drug_code] += flt(d.dosage) - - drug_shortage = dict() - for drug, required_qty in drug_requirement.items(): - available_qty = get_latest_stock_qty(drug, warehouse) - if flt(required_qty) > flt(available_qty): - drug_shortage[drug] = flt(flt(required_qty) - flt(available_qty)) - - return drug_shortage - - -@frappe.whitelist() -def make_difference_stock_entry(docname): - doc = frappe.get_doc('Inpatient Medication Entry', docname) - drug_shortage = get_drug_shortage_map(doc.medication_orders, doc.warehouse) - - if not drug_shortage: - return None - - stock_entry = frappe.new_doc('Stock Entry') - stock_entry.purpose = 'Material Transfer' - stock_entry.set_stock_entry_type() - stock_entry.to_warehouse = doc.warehouse - stock_entry.company = doc.company - cost_center = frappe.get_cached_value('Company', doc.company, 'cost_center') - expense_account = get_account(None, 'expense_account', 'Healthcare Settings', doc.company) - - for drug, shortage_qty in drug_shortage.items(): - se_child = stock_entry.append('items') - se_child.item_code = drug - se_child.item_name = frappe.db.get_value('Item', drug, 'stock_uom') - se_child.uom = frappe.db.get_value('Item', drug, 'stock_uom') - se_child.stock_uom = se_child.uom - se_child.qty = flt(shortage_qty) - se_child.t_warehouse = doc.warehouse - # in stock uom - se_child.conversion_factor = 1 - se_child.cost_center = cost_center - se_child.expense_account = expense_account - - return stock_entry diff --git a/erpnext/healthcare/doctype/inpatient_medication_entry/inpatient_medication_entry_dashboard.py b/erpnext/healthcare/doctype/inpatient_medication_entry/inpatient_medication_entry_dashboard.py deleted file mode 100644 index ca9364d66a1..00000000000 --- a/erpnext/healthcare/doctype/inpatient_medication_entry/inpatient_medication_entry_dashboard.py +++ /dev/null @@ -1,18 +0,0 @@ -from __future__ import unicode_literals - -from frappe import _ - - -def get_data(): - return { - 'fieldname': 'against_imoe', - 'internal_links': { - 'Inpatient Medication Order': ['medication_orders', 'against_imo'] - }, - 'transactions': [ - { - 'label': _('Reference'), - 'items': ['Inpatient Medication Order'] - } - ] - } diff --git a/erpnext/healthcare/doctype/inpatient_medication_entry/test_inpatient_medication_entry.py b/erpnext/healthcare/doctype/inpatient_medication_entry/test_inpatient_medication_entry.py deleted file mode 100644 index dde7739f7ac..00000000000 --- a/erpnext/healthcare/doctype/inpatient_medication_entry/test_inpatient_medication_entry.py +++ /dev/null @@ -1,174 +0,0 @@ -# -*- coding: utf-8 -*- -# Copyright (c) 2020, Frappe Technologies Pvt. Ltd. and Contributors -# See license.txt -from __future__ import unicode_literals - -import unittest - -import frappe -from frappe.utils import add_days, getdate, now_datetime - -from erpnext.healthcare.doctype.healthcare_settings.healthcare_settings import get_account -from erpnext.healthcare.doctype.inpatient_medication_entry.inpatient_medication_entry import ( - get_drug_shortage_map, - make_difference_stock_entry, -) -from erpnext.healthcare.doctype.inpatient_medication_order.test_inpatient_medication_order import ( - create_ipme, - create_ipmo, -) -from erpnext.healthcare.doctype.inpatient_record.inpatient_record import ( - admit_patient, - discharge_patient, - schedule_discharge, -) -from erpnext.healthcare.doctype.inpatient_record.test_inpatient_record import ( - create_inpatient, - create_patient, - get_healthcare_service_unit, - mark_invoiced_inpatient_occupancy, -) - - -class TestInpatientMedicationEntry(unittest.TestCase): - def setUp(self): - frappe.db.sql("""delete from `tabInpatient Record`""") - frappe.db.sql("""delete from `tabInpatient Medication Order`""") - frappe.db.sql("""delete from `tabInpatient Medication Entry`""") - self.patient = create_patient() - - # Admit - ip_record = create_inpatient(self.patient) - ip_record.expected_length_of_stay = 0 - ip_record.save() - ip_record.reload() - service_unit = get_healthcare_service_unit() - admit_patient(ip_record, service_unit, now_datetime()) - self.ip_record = ip_record - - def test_filters_for_fetching_pending_mo(self): - ipmo = create_ipmo(self.patient) - ipmo.submit() - ipmo.reload() - - date = add_days(getdate(), -1) - filters = frappe._dict( - from_date=date, - to_date=date, - from_time='', - to_time='', - item_code='Dextromethorphan', - patient=self.patient - ) - - ipme = create_ipme(filters, update_stock=0) - - # 3 dosages per day - self.assertEqual(len(ipme.medication_orders), 3) - self.assertEqual(getdate(ipme.medication_orders[0].datetime), date) - - def test_ipme_with_stock_update(self): - ipmo = create_ipmo(self.patient) - ipmo.submit() - ipmo.reload() - - date = add_days(getdate(), -1) - filters = frappe._dict( - from_date=date, - to_date=date, - from_time='', - to_time='', - item_code='Dextromethorphan', - patient=self.patient - ) - - make_stock_entry() - ipme = create_ipme(filters, update_stock=1) - ipme.submit() - ipme.reload() - - # test order completed - is_order_completed = frappe.db.get_value('Inpatient Medication Order Entry', - ipme.medication_orders[0].against_imoe, 'is_completed') - self.assertEqual(is_order_completed, 1) - - # test stock entry - stock_entry = frappe.db.exists('Stock Entry', {'inpatient_medication_entry': ipme.name}) - self.assertTrue(stock_entry) - - # check references - stock_entry = frappe.get_doc('Stock Entry', stock_entry) - self.assertEqual(stock_entry.items[0].patient, self.patient) - self.assertEqual(stock_entry.items[0].inpatient_medication_entry_child, ipme.medication_orders[0].name) - - def test_drug_shortage_stock_entry(self): - ipmo = create_ipmo(self.patient) - ipmo.submit() - ipmo.reload() - - date = add_days(getdate(), -1) - filters = frappe._dict( - from_date=date, - to_date=date, - from_time='', - to_time='', - item_code='Dextromethorphan', - patient=self.patient - ) - - # check drug shortage - ipme = create_ipme(filters, update_stock=1) - ipme.warehouse = 'Finished Goods - _TC' - ipme.save() - drug_shortage = get_drug_shortage_map(ipme.medication_orders, ipme.warehouse) - self.assertEqual(drug_shortage.get('Dextromethorphan'), 3) - - # check material transfer for drug shortage - make_stock_entry() - stock_entry = make_difference_stock_entry(ipme.name) - self.assertEqual(stock_entry.items[0].item_code, 'Dextromethorphan') - self.assertEqual(stock_entry.items[0].qty, 3) - stock_entry.from_warehouse = 'Stores - _TC' - stock_entry.submit() - - ipme.reload() - ipme.submit() - - def tearDown(self): - # cleanup - Discharge - schedule_discharge(frappe.as_json({'patient': self.patient})) - self.ip_record.reload() - mark_invoiced_inpatient_occupancy(self.ip_record) - - self.ip_record.reload() - discharge_patient(self.ip_record) - - for entry in frappe.get_all('Inpatient Medication Entry'): - doc = frappe.get_doc('Inpatient Medication Entry', entry.name) - doc.cancel() - - for entry in frappe.get_all('Inpatient Medication Order'): - doc = frappe.get_doc('Inpatient Medication Order', entry.name) - doc.cancel() - -def make_stock_entry(warehouse=None): - frappe.db.set_value('Company', '_Test Company', { - 'stock_adjustment_account': 'Stock Adjustment - _TC', - 'default_inventory_account': 'Stock In Hand - _TC' - }) - stock_entry = frappe.new_doc('Stock Entry') - stock_entry.stock_entry_type = 'Material Receipt' - stock_entry.company = '_Test Company' - stock_entry.to_warehouse = warehouse or 'Stores - _TC' - expense_account = get_account(None, 'expense_account', 'Healthcare Settings', '_Test Company') - se_child = stock_entry.append('items') - se_child.item_code = 'Dextromethorphan' - se_child.item_name = 'Dextromethorphan' - se_child.uom = 'Nos' - se_child.stock_uom = 'Nos' - se_child.qty = 6 - se_child.t_warehouse = 'Stores - _TC' - # in stock uom - se_child.conversion_factor = 1.0 - se_child.expense_account = expense_account - stock_entry.submit() diff --git a/erpnext/healthcare/doctype/inpatient_medication_entry_detail/inpatient_medication_entry_detail.json b/erpnext/healthcare/doctype/inpatient_medication_entry_detail/inpatient_medication_entry_detail.json deleted file mode 100644 index e3d7212169e..00000000000 --- a/erpnext/healthcare/doctype/inpatient_medication_entry_detail/inpatient_medication_entry_detail.json +++ /dev/null @@ -1,163 +0,0 @@ -{ - "actions": [], - "creation": "2020-09-25 14:56:32.636569", - "doctype": "DocType", - "editable_grid": 1, - "engine": "InnoDB", - "field_order": [ - "patient", - "patient_name", - "inpatient_record", - "column_break_4", - "service_unit", - "datetime", - "medication_details_section", - "drug_code", - "drug_name", - "dosage", - "available_qty", - "dosage_form", - "column_break_10", - "instructions", - "references_section", - "against_imo", - "against_imoe" - ], - "fields": [ - { - "columns": 2, - "fieldname": "patient", - "fieldtype": "Link", - "in_list_view": 1, - "label": "Patient", - "options": "Patient", - "reqd": 1 - }, - { - "fetch_from": "patient.patient_name", - "fieldname": "patient_name", - "fieldtype": "Data", - "label": "Patient Name", - "read_only": 1 - }, - { - "columns": 2, - "fieldname": "drug_code", - "fieldtype": "Link", - "in_list_view": 1, - "label": "Drug Code", - "options": "Item", - "reqd": 1 - }, - { - "fetch_from": "drug_code.item_name", - "fieldname": "drug_name", - "fieldtype": "Data", - "label": "Drug Name", - "read_only": 1 - }, - { - "columns": 1, - "fieldname": "dosage", - "fieldtype": "Float", - "in_list_view": 1, - "label": "Dosage", - "reqd": 1 - }, - { - "fieldname": "dosage_form", - "fieldtype": "Link", - "label": "Dosage Form", - "options": "Dosage Form" - }, - { - "fetch_from": "patient.inpatient_record", - "fieldname": "inpatient_record", - "fieldtype": "Link", - "label": "Inpatient Record", - "options": "Inpatient Record", - "read_only": 1 - }, - { - "collapsible": 1, - "fieldname": "references_section", - "fieldtype": "Section Break", - "label": "References" - }, - { - "fieldname": "column_break_4", - "fieldtype": "Column Break" - }, - { - "fieldname": "medication_details_section", - "fieldtype": "Section Break", - "label": "Medication Details" - }, - { - "fieldname": "column_break_10", - "fieldtype": "Column Break" - }, - { - "columns": 3, - "fieldname": "datetime", - "fieldtype": "Datetime", - "in_list_view": 1, - "label": "Datetime", - "reqd": 1 - }, - { - "fieldname": "instructions", - "fieldtype": "Small Text", - "label": "Instructions" - }, - { - "columns": 2, - "fieldname": "service_unit", - "fieldtype": "Link", - "in_list_view": 1, - "label": "Service Unit", - "options": "Healthcare Service Unit", - "read_only": 1, - "reqd": 1 - }, - { - "fieldname": "against_imo", - "fieldtype": "Link", - "label": "Against Inpatient Medication Order", - "no_copy": 1, - "options": "Inpatient Medication Order", - "print_hide": 1, - "read_only": 1 - }, - { - "fieldname": "against_imoe", - "fieldtype": "Data", - "label": "Against Inpatient Medication Order Entry", - "no_copy": 1, - "print_hide": 1, - "read_only": 1 - }, - { - "fieldname": "available_qty", - "fieldtype": "Float", - "hidden": 1, - "label": "Available Qty", - "no_copy": 1, - "print_hide": 1, - "read_only": 1 - } - ], - "index_web_pages_for_search": 1, - "istable": 1, - "links": [], - "modified": "2020-09-30 14:48:23.648223", - "modified_by": "Administrator", - "module": "Healthcare", - "name": "Inpatient Medication Entry Detail", - "owner": "Administrator", - "permissions": [], - "quick_entry": 1, - "sort_field": "modified", - "sort_order": "DESC", - "track_changes": 1 -} \ No newline at end of file diff --git a/erpnext/healthcare/doctype/inpatient_medication_entry_detail/inpatient_medication_entry_detail.py b/erpnext/healthcare/doctype/inpatient_medication_entry_detail/inpatient_medication_entry_detail.py deleted file mode 100644 index 91734312d4a..00000000000 --- a/erpnext/healthcare/doctype/inpatient_medication_entry_detail/inpatient_medication_entry_detail.py +++ /dev/null @@ -1,12 +0,0 @@ -# -*- coding: utf-8 -*- -# Copyright (c) 2020, Frappe Technologies Pvt. Ltd. and contributors -# For license information, please see license.txt - -from __future__ import unicode_literals - -# import frappe -from frappe.model.document import Document - - -class InpatientMedicationEntryDetail(Document): - pass diff --git a/erpnext/healthcare/doctype/inpatient_medication_order/__init__.py b/erpnext/healthcare/doctype/inpatient_medication_order/__init__.py deleted file mode 100644 index e69de29bb2d..00000000000 diff --git a/erpnext/healthcare/doctype/inpatient_medication_order/inpatient_medication_order.js b/erpnext/healthcare/doctype/inpatient_medication_order/inpatient_medication_order.js deleted file mode 100644 index 690e2e7a900..00000000000 --- a/erpnext/healthcare/doctype/inpatient_medication_order/inpatient_medication_order.js +++ /dev/null @@ -1,107 +0,0 @@ -// Copyright (c) 2020, Frappe Technologies Pvt. Ltd. and contributors -// For license information, please see license.txt - -frappe.ui.form.on('Inpatient Medication Order', { - refresh: function(frm) { - if (frm.doc.docstatus === 1) { - frm.trigger("show_progress"); - } - - frm.events.show_medication_order_button(frm); - - frm.set_query('patient', () => { - return { - filters: { - 'inpatient_record': ['!=', ''], - 'inpatient_status': 'Admitted' - } - }; - }); - }, - - show_medication_order_button: function(frm) { - frm.fields_dict['medication_orders'].grid.wrapper.find('.grid-add-row').hide(); - frm.fields_dict['medication_orders'].grid.add_custom_button(__('Add Medication Orders'), () => { - let d = new frappe.ui.Dialog({ - title: __('Add Medication Orders'), - fields: [ - { - fieldname: 'drug_code', - label: __('Drug'), - fieldtype: 'Link', - options: 'Item', - reqd: 1, - "get_query": function () { - return { - filters: {'is_stock_item': 1} - }; - } - }, - { - fieldname: 'dosage', - label: __('Dosage'), - fieldtype: 'Link', - options: 'Prescription Dosage', - reqd: 1 - }, - { - fieldname: 'period', - label: __('Period'), - fieldtype: 'Link', - options: 'Prescription Duration', - reqd: 1 - }, - { - fieldname: 'dosage_form', - label: __('Dosage Form'), - fieldtype: 'Link', - options: 'Dosage Form', - reqd: 1 - } - ], - primary_action_label: __('Add'), - primary_action: () => { - let values = d.get_values(); - if (values) { - frm.call({ - doc: frm.doc, - method: 'add_order_entries', - args: { - order: values - }, - freeze: true, - freeze_message: __('Adding Order Entries'), - callback: function() { - frm.refresh_field('medication_orders'); - } - }); - } - }, - }); - d.show(); - }); - }, - - show_progress: function(frm) { - let bars = []; - let message = ''; - - // completed sessions - let title = __('{0} medication orders completed', [frm.doc.completed_orders]); - if (frm.doc.completed_orders === 1) { - title = __('{0} medication order completed', [frm.doc.completed_orders]); - } - title += __(' out of {0}', [frm.doc.total_orders]); - - bars.push({ - 'title': title, - 'width': (frm.doc.completed_orders / frm.doc.total_orders * 100) + '%', - 'progress_class': 'progress-bar-success' - }); - if (bars[0].width == '0%') { - bars[0].width = '0.5%'; - } - message = title; - frm.dashboard.add_progress(__('Status'), bars, message); - } -}); diff --git a/erpnext/healthcare/doctype/inpatient_medication_order/inpatient_medication_order.json b/erpnext/healthcare/doctype/inpatient_medication_order/inpatient_medication_order.json deleted file mode 100644 index e31d2e3e36c..00000000000 --- a/erpnext/healthcare/doctype/inpatient_medication_order/inpatient_medication_order.json +++ /dev/null @@ -1,196 +0,0 @@ -{ - "actions": [], - "autoname": "naming_series:", - "creation": "2020-09-14 18:33:56.715736", - "doctype": "DocType", - "editable_grid": 1, - "engine": "InnoDB", - "field_order": [ - "patient_details_section", - "naming_series", - "patient_encounter", - "patient", - "patient_name", - "patient_age", - "inpatient_record", - "column_break_6", - "company", - "status", - "practitioner", - "start_date", - "end_date", - "medication_orders_section", - "medication_orders", - "section_break_16", - "total_orders", - "column_break_18", - "completed_orders", - "amended_from" - ], - "fields": [ - { - "fieldname": "patient_details_section", - "fieldtype": "Section Break", - "label": "Patient Details" - }, - { - "fieldname": "naming_series", - "fieldtype": "Select", - "label": "Naming Series", - "options": "HLC-IMO-.YYYY.-" - }, - { - "fieldname": "patient_encounter", - "fieldtype": "Link", - "in_list_view": 1, - "label": "Patient Encounter", - "options": "Patient Encounter" - }, - { - "fetch_from": "patient_encounter.patient", - "fieldname": "patient", - "fieldtype": "Link", - "label": "Patient", - "options": "Patient", - "read_only_depends_on": "patient_encounter", - "reqd": 1 - }, - { - "fetch_from": "patient.patient_name", - "fieldname": "patient_name", - "fieldtype": "Data", - "label": "Patient Name", - "read_only": 1 - }, - { - "fieldname": "patient_age", - "fieldtype": "Data", - "label": "Patient Age", - "read_only": 1 - }, - { - "fieldname": "column_break_6", - "fieldtype": "Column Break" - }, - { - "fetch_from": "patient.inpatient_record", - "fieldname": "inpatient_record", - "fieldtype": "Link", - "in_list_view": 1, - "label": "Inpatient Record", - "options": "Inpatient Record", - "read_only": 1, - "reqd": 1 - }, - { - "fetch_from": "patient_encounter.practitioner", - "fieldname": "practitioner", - "fieldtype": "Link", - "in_list_view": 1, - "label": "Healthcare Practitioner", - "options": "Healthcare Practitioner", - "read_only_depends_on": "patient_encounter" - }, - { - "fieldname": "start_date", - "fieldtype": "Date", - "in_list_view": 1, - "label": "Start Date", - "reqd": 1 - }, - { - "fieldname": "end_date", - "fieldtype": "Date", - "label": "End Date", - "read_only": 1 - }, - { - "depends_on": "eval: doc.patient && doc.start_date", - "fieldname": "medication_orders_section", - "fieldtype": "Section Break", - "label": "Medication Orders" - }, - { - "fieldname": "medication_orders", - "fieldtype": "Table", - "label": "Medication Orders", - "options": "Inpatient Medication Order Entry" - }, - { - "fieldname": "company", - "fieldtype": "Link", - "label": "Company", - "options": "Company", - "reqd": 1 - }, - { - "fieldname": "amended_from", - "fieldtype": "Link", - "label": "Amended From", - "no_copy": 1, - "options": "Inpatient Medication Order", - "print_hide": 1, - "read_only": 1 - }, - { - "fieldname": "status", - "fieldtype": "Select", - "in_list_view": 1, - "in_standard_filter": 1, - "label": "Status", - "options": "\nDraft\nSubmitted\nPending\nIn Process\nCompleted\nCancelled", - "read_only": 1 - }, - { - "collapsible": 1, - "fieldname": "section_break_16", - "fieldtype": "Section Break", - "label": "Other Details" - }, - { - "fieldname": "total_orders", - "fieldtype": "Float", - "label": "Total Orders", - "no_copy": 1, - "read_only": 1 - }, - { - "fieldname": "column_break_18", - "fieldtype": "Column Break" - }, - { - "fieldname": "completed_orders", - "fieldtype": "Float", - "label": "Completed Orders", - "no_copy": 1, - "read_only": 1 - } - ], - "index_web_pages_for_search": 1, - "is_submittable": 1, - "links": [], - "modified": "2020-09-30 21:53:27.128591", - "modified_by": "Administrator", - "module": "Healthcare", - "name": "Inpatient Medication Order", - "owner": "Administrator", - "permissions": [ - { - "create": 1, - "delete": 1, - "email": 1, - "export": 1, - "print": 1, - "read": 1, - "report": 1, - "role": "System Manager", - "share": 1, - "write": 1 - } - ], - "search_fields": "patient_encounter, patient", - "sort_field": "modified", - "sort_order": "DESC", - "title_field": "patient", - "track_changes": 1 -} \ No newline at end of file diff --git a/erpnext/healthcare/doctype/inpatient_medication_order/inpatient_medication_order.py b/erpnext/healthcare/doctype/inpatient_medication_order/inpatient_medication_order.py deleted file mode 100644 index 2e6d73208f7..00000000000 --- a/erpnext/healthcare/doctype/inpatient_medication_order/inpatient_medication_order.py +++ /dev/null @@ -1,78 +0,0 @@ -# -*- coding: utf-8 -*- -# Copyright (c) 2020, Frappe Technologies Pvt. Ltd. and contributors -# For license information, please see license.txt - -from __future__ import unicode_literals - -import frappe -from frappe import _ -from frappe.model.document import Document -from frappe.utils import cstr - -from erpnext.healthcare.doctype.patient_encounter.patient_encounter import get_prescription_dates - - -class InpatientMedicationOrder(Document): - def validate(self): - self.validate_inpatient() - self.validate_duplicate() - self.set_total_orders() - self.set_status() - - def on_submit(self): - self.validate_inpatient() - self.set_status() - - def on_cancel(self): - self.set_status() - - def validate_inpatient(self): - if not self.inpatient_record: - frappe.throw(_('No Inpatient Record found against patient {0}').format(self.patient)) - - def validate_duplicate(self): - existing_mo = frappe.db.exists('Inpatient Medication Order', { - 'patient_encounter': self.patient_encounter, - 'docstatus': ('!=', 2), - 'name': ('!=', self.name) - }) - if existing_mo: - frappe.throw(_('An Inpatient Medication Order {0} against Patient Encounter {1} already exists.').format( - existing_mo, self.patient_encounter), frappe.DuplicateEntryError) - - def set_total_orders(self): - self.db_set('total_orders', len(self.medication_orders)) - - def set_status(self): - status = { - "0": "Draft", - "1": "Submitted", - "2": "Cancelled" - }[cstr(self.docstatus or 0)] - - if self.docstatus == 1: - if not self.completed_orders: - status = 'Pending' - elif self.completed_orders < self.total_orders: - status = 'In Process' - else: - status = 'Completed' - - self.db_set('status', status) - - @frappe.whitelist() - def add_order_entries(self, order): - if order.get('drug_code'): - dosage = frappe.get_doc('Prescription Dosage', order.get('dosage')) - dates = get_prescription_dates(order.get('period'), self.start_date) - for date in dates: - for dose in dosage.dosage_strength: - entry = self.append('medication_orders') - entry.drug = order.get('drug_code') - entry.drug_name = frappe.db.get_value('Item', order.get('drug_code'), 'item_name') - entry.dosage = dose.strength - entry.dosage_form = order.get('dosage_form') - entry.date = date - entry.time = dose.strength_time - self.end_date = dates[-1] - return diff --git a/erpnext/healthcare/doctype/inpatient_medication_order/inpatient_medication_order_list.js b/erpnext/healthcare/doctype/inpatient_medication_order/inpatient_medication_order_list.js deleted file mode 100644 index 1c318768ea7..00000000000 --- a/erpnext/healthcare/doctype/inpatient_medication_order/inpatient_medication_order_list.js +++ /dev/null @@ -1,16 +0,0 @@ -frappe.listview_settings['Inpatient Medication Order'] = { - add_fields: ["status"], - filters: [["status", "!=", "Cancelled"]], - get_indicator: function(doc) { - if (doc.status === "Pending") { - return [__("Pending"), "orange", "status,=,Pending"]; - - } else if (doc.status === "In Process") { - return [__("In Process"), "blue", "status,=,In Process"]; - - } else if (doc.status === "Completed") { - return [__("Completed"), "green", "status,=,Completed"]; - - } - } -}; diff --git a/erpnext/healthcare/doctype/inpatient_medication_order/test_inpatient_medication_order.py b/erpnext/healthcare/doctype/inpatient_medication_order/test_inpatient_medication_order.py deleted file mode 100644 index 477f8c97615..00000000000 --- a/erpnext/healthcare/doctype/inpatient_medication_order/test_inpatient_medication_order.py +++ /dev/null @@ -1,154 +0,0 @@ -# -*- coding: utf-8 -*- -# Copyright (c) 2020, Frappe Technologies Pvt. Ltd. and Contributors -# See license.txt -from __future__ import unicode_literals - -import unittest - -import frappe -from frappe.utils import add_days, getdate, now_datetime - -from erpnext.healthcare.doctype.inpatient_record.inpatient_record import ( - admit_patient, - discharge_patient, - schedule_discharge, -) -from erpnext.healthcare.doctype.inpatient_record.test_inpatient_record import ( - create_inpatient, - create_patient, - get_healthcare_service_unit, - mark_invoiced_inpatient_occupancy, -) - - -class TestInpatientMedicationOrder(unittest.TestCase): - def setUp(self): - frappe.db.sql("""delete from `tabInpatient Record`""") - self.patient = create_patient() - - # Admit - ip_record = create_inpatient(self.patient) - ip_record.expected_length_of_stay = 0 - ip_record.save() - ip_record.reload() - service_unit = get_healthcare_service_unit() - admit_patient(ip_record, service_unit, now_datetime()) - self.ip_record = ip_record - - def test_order_creation(self): - ipmo = create_ipmo(self.patient) - ipmo.submit() - ipmo.reload() - - # 3 dosages per day for 2 days - self.assertEqual(len(ipmo.medication_orders), 6) - self.assertEqual(ipmo.medication_orders[0].date, add_days(getdate(), -1)) - - prescription_dosage = frappe.get_doc('Prescription Dosage', '1-1-1') - for i in range(len(prescription_dosage.dosage_strength)): - self.assertEqual(ipmo.medication_orders[i].time, prescription_dosage.dosage_strength[i].strength_time) - - self.assertEqual(ipmo.medication_orders[3].date, getdate()) - - def test_inpatient_validation(self): - # Discharge - schedule_discharge(frappe.as_json({'patient': self.patient})) - - self.ip_record.reload() - mark_invoiced_inpatient_occupancy(self.ip_record) - - self.ip_record.reload() - discharge_patient(self.ip_record) - - ipmo = create_ipmo(self.patient) - # inpatient validation - self.assertRaises(frappe.ValidationError, ipmo.insert) - - def test_status(self): - ipmo = create_ipmo(self.patient) - ipmo.submit() - ipmo.reload() - - self.assertEqual(ipmo.status, 'Pending') - - filters = frappe._dict(from_date=add_days(getdate(), -1), to_date=add_days(getdate(), -1), from_time='', to_time='') - ipme = create_ipme(filters) - ipme.submit() - ipmo.reload() - self.assertEqual(ipmo.status, 'In Process') - - filters = frappe._dict(from_date=getdate(), to_date=getdate(), from_time='', to_time='') - ipme = create_ipme(filters) - ipme.submit() - ipmo.reload() - self.assertEqual(ipmo.status, 'Completed') - - def tearDown(self): - if frappe.db.get_value('Patient', self.patient, 'inpatient_record'): - # cleanup - Discharge - schedule_discharge(frappe.as_json({'patient': self.patient})) - self.ip_record.reload() - mark_invoiced_inpatient_occupancy(self.ip_record) - - self.ip_record.reload() - discharge_patient(self.ip_record) - - for doctype in ["Inpatient Medication Entry", "Inpatient Medication Order"]: - frappe.db.sql("delete from `tab{doctype}`".format(doctype=doctype)) - -def create_dosage_form(): - if not frappe.db.exists('Dosage Form', 'Tablet'): - frappe.get_doc({ - 'doctype': 'Dosage Form', - 'dosage_form': 'Tablet' - }).insert() - -def create_drug(item=None): - if not item: - item = 'Dextromethorphan' - drug = frappe.db.exists('Item', {'item_code': 'Dextromethorphan'}) - if not drug: - drug = frappe.get_doc({ - 'doctype': 'Item', - 'item_code': 'Dextromethorphan', - 'item_name': 'Dextromethorphan', - 'item_group': 'Products', - 'stock_uom': 'Nos', - 'is_stock_item': 1, - 'valuation_rate': 50, - 'opening_stock': 20 - }).insert() - -def get_orders(): - create_dosage_form() - create_drug() - return { - 'drug_code': 'Dextromethorphan', - 'drug_name': 'Dextromethorphan', - 'dosage': '1-1-1', - 'dosage_form': 'Tablet', - 'period': '2 Day' - } - -def create_ipmo(patient): - orders = get_orders() - ipmo = frappe.new_doc('Inpatient Medication Order') - ipmo.patient = patient - ipmo.company = '_Test Company' - ipmo.start_date = add_days(getdate(), -1) - ipmo.add_order_entries(orders) - - return ipmo - -def create_ipme(filters, update_stock=0): - ipme = frappe.new_doc('Inpatient Medication Entry') - ipme.company = '_Test Company' - ipme.posting_date = getdate() - ipme.update_stock = update_stock - if update_stock: - ipme.warehouse = 'Stores - _TC' - for key, value in filters.items(): - ipme.set(key, value) - ipme = ipme.get_medication_orders() - - return ipme diff --git a/erpnext/healthcare/doctype/inpatient_medication_order_entry/__init__.py b/erpnext/healthcare/doctype/inpatient_medication_order_entry/__init__.py deleted file mode 100644 index e69de29bb2d..00000000000 diff --git a/erpnext/healthcare/doctype/inpatient_medication_order_entry/inpatient_medication_order_entry.json b/erpnext/healthcare/doctype/inpatient_medication_order_entry/inpatient_medication_order_entry.json deleted file mode 100644 index 72999a908eb..00000000000 --- a/erpnext/healthcare/doctype/inpatient_medication_order_entry/inpatient_medication_order_entry.json +++ /dev/null @@ -1,94 +0,0 @@ -{ - "actions": [], - "creation": "2020-09-14 21:51:30.259164", - "doctype": "DocType", - "editable_grid": 1, - "engine": "InnoDB", - "field_order": [ - "drug", - "drug_name", - "dosage", - "dosage_form", - "instructions", - "column_break_4", - "date", - "time", - "is_completed" - ], - "fields": [ - { - "fieldname": "drug", - "fieldtype": "Link", - "in_list_view": 1, - "label": "Drug", - "options": "Item", - "reqd": 1 - }, - { - "fetch_from": "drug.item_name", - "fieldname": "drug_name", - "fieldtype": "Data", - "label": "Drug Name", - "read_only": 1 - }, - { - "fieldname": "dosage", - "fieldtype": "Float", - "in_list_view": 1, - "label": "Dosage", - "reqd": 1 - }, - { - "fieldname": "dosage_form", - "fieldtype": "Link", - "in_list_view": 1, - "label": "Dosage Form", - "options": "Dosage Form", - "reqd": 1 - }, - { - "fieldname": "column_break_4", - "fieldtype": "Column Break" - }, - { - "fieldname": "date", - "fieldtype": "Date", - "in_list_view": 1, - "label": "Date", - "reqd": 1 - }, - { - "fieldname": "time", - "fieldtype": "Time", - "in_list_view": 1, - "label": "Time", - "reqd": 1 - }, - { - "default": "0", - "fieldname": "is_completed", - "fieldtype": "Check", - "label": "Is Order Completed", - "no_copy": 1, - "read_only": 1 - }, - { - "fieldname": "instructions", - "fieldtype": "Small Text", - "label": "Instructions" - } - ], - "index_web_pages_for_search": 1, - "istable": 1, - "links": [], - "modified": "2020-09-30 14:03:26.755925", - "modified_by": "Administrator", - "module": "Healthcare", - "name": "Inpatient Medication Order Entry", - "owner": "Administrator", - "permissions": [], - "quick_entry": 1, - "sort_field": "modified", - "sort_order": "DESC", - "track_changes": 1 -} \ No newline at end of file diff --git a/erpnext/healthcare/doctype/inpatient_medication_order_entry/inpatient_medication_order_entry.py b/erpnext/healthcare/doctype/inpatient_medication_order_entry/inpatient_medication_order_entry.py deleted file mode 100644 index 15800ad15f6..00000000000 --- a/erpnext/healthcare/doctype/inpatient_medication_order_entry/inpatient_medication_order_entry.py +++ /dev/null @@ -1,12 +0,0 @@ -# -*- coding: utf-8 -*- -# Copyright (c) 2020, Frappe Technologies Pvt. Ltd. and contributors -# For license information, please see license.txt - -from __future__ import unicode_literals - -# import frappe -from frappe.model.document import Document - - -class InpatientMedicationOrderEntry(Document): - pass diff --git a/erpnext/healthcare/doctype/inpatient_occupancy/__init__.py b/erpnext/healthcare/doctype/inpatient_occupancy/__init__.py deleted file mode 100644 index e69de29bb2d..00000000000 diff --git a/erpnext/healthcare/doctype/inpatient_occupancy/inpatient_occupancy.json b/erpnext/healthcare/doctype/inpatient_occupancy/inpatient_occupancy.json deleted file mode 100644 index 3fa98b66780..00000000000 --- a/erpnext/healthcare/doctype/inpatient_occupancy/inpatient_occupancy.json +++ /dev/null @@ -1,64 +0,0 @@ -{ - "actions": [], - "creation": "2018-07-12 12:07:36.932333", - "doctype": "DocType", - "editable_grid": 1, - "engine": "InnoDB", - "field_order": [ - "service_unit", - "check_in", - "left", - "check_out", - "invoiced" - ], - "fields": [ - { - "fieldname": "service_unit", - "fieldtype": "Link", - "in_list_view": 1, - "label": "Healthcare Service Unit", - "options": "Healthcare Service Unit", - "reqd": 1 - }, - { - "fieldname": "check_in", - "fieldtype": "Datetime", - "in_list_view": 1, - "label": "Check In" - }, - { - "default": "0", - "fieldname": "left", - "fieldtype": "Check", - "label": "Left", - "read_only": 1, - "search_index": 1 - }, - { - "fieldname": "check_out", - "fieldtype": "Datetime", - "label": "Check Out" - }, - { - "default": "0", - "fieldname": "invoiced", - "fieldtype": "Check", - "label": "Invoiced", - "read_only": 1 - } - ], - "index_web_pages_for_search": 1, - "istable": 1, - "links": [], - "modified": "2021-03-18 15:08:54.634132", - "modified_by": "Administrator", - "module": "Healthcare", - "name": "Inpatient Occupancy", - "owner": "Administrator", - "permissions": [], - "quick_entry": 1, - "restrict_to_domain": "Healthcare", - "sort_field": "modified", - "sort_order": "DESC", - "track_changes": 1 -} \ No newline at end of file diff --git a/erpnext/healthcare/doctype/inpatient_occupancy/inpatient_occupancy.py b/erpnext/healthcare/doctype/inpatient_occupancy/inpatient_occupancy.py deleted file mode 100644 index c8f3296d0db..00000000000 --- a/erpnext/healthcare/doctype/inpatient_occupancy/inpatient_occupancy.py +++ /dev/null @@ -1,11 +0,0 @@ -# -*- coding: utf-8 -*- -# Copyright (c) 2018, Frappe Technologies Pvt. Ltd. and contributors -# For license information, please see license.txt - -from __future__ import unicode_literals - -from frappe.model.document import Document - - -class InpatientOccupancy(Document): - pass diff --git a/erpnext/healthcare/doctype/inpatient_record/__init__.py b/erpnext/healthcare/doctype/inpatient_record/__init__.py deleted file mode 100644 index e69de29bb2d..00000000000 diff --git a/erpnext/healthcare/doctype/inpatient_record/inpatient_record.js b/erpnext/healthcare/doctype/inpatient_record/inpatient_record.js deleted file mode 100644 index 60f0f9d56d6..00000000000 --- a/erpnext/healthcare/doctype/inpatient_record/inpatient_record.js +++ /dev/null @@ -1,214 +0,0 @@ -// Copyright (c) 2018, Frappe Technologies Pvt. Ltd. and contributors -// For license information, please see license.txt - -frappe.ui.form.on('Inpatient Record', { - setup: function(frm) { - frm.get_field('drug_prescription').grid.editable_fields = [ - {fieldname: 'drug_code', columns: 2}, - {fieldname: 'drug_name', columns: 2}, - {fieldname: 'dosage', columns: 2}, - {fieldname: 'period', columns: 2} - ]; - }, - refresh: function(frm) { - if (!frm.doc.__islocal && (frm.doc.status == 'Admission Scheduled' || frm.doc.status == 'Admitted')) { - frm.enable_save(); - } else { - frm.disable_save(); - } - - if (!frm.doc.__islocal && frm.doc.status == 'Admission Scheduled') { - frm.add_custom_button(__('Admit'), function() { - admit_patient_dialog(frm); - } ); - } - - if (!frm.doc.__islocal && frm.doc.status == 'Discharge Scheduled') { - frm.add_custom_button(__('Discharge'), function() { - discharge_patient(frm); - } ); - } - if (!frm.doc.__islocal && frm.doc.status != 'Admitted') { - frm.disable_save(); - frm.set_df_property('btn_transfer', 'hidden', 1); - } else { - frm.set_df_property('btn_transfer', 'hidden', 0); - } - }, - btn_transfer: function(frm) { - transfer_patient_dialog(frm); - } -}); - -let discharge_patient = function(frm) { - frappe.call({ - doc: frm.doc, - method: 'discharge', - callback: function(data) { - if (!data.exc) { - frm.reload_doc(); - } - }, - freeze: true, - freeze_message: __('Processing Inpatient Discharge') - }); -}; - -let admit_patient_dialog = function(frm) { - let dialog = new frappe.ui.Dialog({ - title: 'Admit Patient', - width: 100, - fields: [ - {fieldtype: 'Link', label: 'Service Unit Type', fieldname: 'service_unit_type', - options: 'Healthcare Service Unit Type', default: frm.doc.admission_service_unit_type - }, - {fieldtype: 'Link', label: 'Service Unit', fieldname: 'service_unit', - options: 'Healthcare Service Unit', reqd: 1 - }, - {fieldtype: 'Datetime', label: 'Admission Datetime', fieldname: 'check_in', - reqd: 1, default: frappe.datetime.now_datetime() - }, - {fieldtype: 'Date', label: 'Expected Discharge', fieldname: 'expected_discharge', - default: frm.doc.expected_length_of_stay ? frappe.datetime.add_days(frappe.datetime.now_datetime(), frm.doc.expected_length_of_stay) : '' - } - ], - primary_action_label: __('Admit'), - primary_action : function(){ - let service_unit = dialog.get_value('service_unit'); - let check_in = dialog.get_value('check_in'); - let expected_discharge = null; - if (dialog.get_value('expected_discharge')) { - expected_discharge = dialog.get_value('expected_discharge'); - } - if (!service_unit && !check_in) { - return; - } - frappe.call({ - doc: frm.doc, - method: 'admit', - args:{ - 'service_unit': service_unit, - 'check_in': check_in, - 'expected_discharge': expected_discharge - }, - callback: function(data) { - if (!data.exc) { - frm.reload_doc(); - } - }, - freeze: true, - freeze_message: __('Processing Patient Admission') - }); - frm.refresh_fields(); - dialog.hide(); - } - }); - - dialog.fields_dict['service_unit_type'].get_query = function() { - return { - filters: { - 'inpatient_occupancy': 1, - 'allow_appointments': 0 - } - }; - }; - dialog.fields_dict['service_unit'].get_query = function() { - return { - filters: { - 'is_group': 0, - 'company': frm.doc.company, - 'service_unit_type': dialog.get_value('service_unit_type'), - 'occupancy_status' : 'Vacant' - } - }; - }; - - dialog.show(); -}; - -let transfer_patient_dialog = function(frm) { - let dialog = new frappe.ui.Dialog({ - title: 'Transfer Patient', - width: 100, - fields: [ - {fieldtype: 'Link', label: 'Leave From', fieldname: 'leave_from', options: 'Healthcare Service Unit', reqd: 1, read_only:1}, - {fieldtype: 'Link', label: 'Service Unit Type', fieldname: 'service_unit_type', options: 'Healthcare Service Unit Type'}, - {fieldtype: 'Link', label: 'Transfer To', fieldname: 'service_unit', options: 'Healthcare Service Unit', reqd: 1}, - {fieldtype: 'Datetime', label: 'Check In', fieldname: 'check_in', reqd: 1, default: frappe.datetime.now_datetime()} - ], - primary_action_label: __('Transfer'), - primary_action : function() { - let service_unit = null; - let check_in = dialog.get_value('check_in'); - let leave_from = null; - if(dialog.get_value('leave_from')){ - leave_from = dialog.get_value('leave_from'); - } - if(dialog.get_value('service_unit')){ - service_unit = dialog.get_value('service_unit'); - } - if(check_in > frappe.datetime.now_datetime()){ - frappe.msgprint({ - title: __('Not Allowed'), - message: __('Check-in time cannot be greater than the current time'), - indicator: 'red' - }); - return; - } - frappe.call({ - doc: frm.doc, - method: 'transfer', - args:{ - 'service_unit': service_unit, - 'check_in': check_in, - 'leave_from': leave_from - }, - callback: function(data) { - if (!data.exc) { - frm.reload_doc(); - } - }, - freeze: true, - freeze_message: __('Process Transfer') - }); - frm.refresh_fields(); - dialog.hide(); - } - }); - - dialog.fields_dict['leave_from'].get_query = function(){ - return { - query : 'erpnext.healthcare.doctype.inpatient_record.inpatient_record.get_leave_from', - filters: {docname:frm.doc.name} - }; - }; - dialog.fields_dict['service_unit_type'].get_query = function(){ - return { - filters: { - 'inpatient_occupancy': 1, - 'allow_appointments': 0 - } - }; - }; - dialog.fields_dict['service_unit'].get_query = function(){ - return { - filters: { - 'is_group': 0, - 'service_unit_type': dialog.get_value('service_unit_type'), - 'occupancy_status' : 'Vacant' - } - }; - }; - - dialog.show(); - - let not_left_service_unit = null; - for (let inpatient_occupancy in frm.doc.inpatient_occupancies) { - if (frm.doc.inpatient_occupancies[inpatient_occupancy].left != 1) { - not_left_service_unit = frm.doc.inpatient_occupancies[inpatient_occupancy].service_unit; - } - } - dialog.set_values({ - 'leave_from': not_left_service_unit - }); -}; diff --git a/erpnext/healthcare/doctype/inpatient_record/inpatient_record.json b/erpnext/healthcare/doctype/inpatient_record/inpatient_record.json deleted file mode 100644 index 0e1c2ba7664..00000000000 --- a/erpnext/healthcare/doctype/inpatient_record/inpatient_record.json +++ /dev/null @@ -1,507 +0,0 @@ -{ - "actions": [], - "autoname": "naming_series:", - "creation": "2018-07-11 17:48:51.404139", - "doctype": "DocType", - "editable_grid": 1, - "engine": "InnoDB", - "field_order": [ - "section_break_1", - "naming_series", - "patient", - "patient_name", - "gender", - "blood_group", - "dob", - "mobile", - "email", - "phone", - "column_break_8", - "company", - "status", - "scheduled_date", - "admitted_datetime", - "expected_discharge", - "references", - "admission_encounter", - "admission_practitioner", - "medical_department", - "admission_ordered_for", - "expected_length_of_stay", - "admission_service_unit_type", - "cb_admission", - "primary_practitioner", - "secondary_practitioner", - "admission_instruction", - "encounter_details_section", - "chief_complaint", - "column_break_29", - "diagnosis", - "medication_section", - "drug_prescription", - "investigations_section", - "lab_test_prescription", - "procedures_section", - "procedure_prescription", - "rehabilitation_section", - "therapy_plan", - "therapies", - "sb_inpatient_occupancy", - "inpatient_occupancies", - "btn_transfer", - "sb_discharge_details", - "discharge_ordered_date", - "discharge_practitioner", - "discharge_encounter", - "discharge_datetime", - "cb_discharge", - "discharge_instructions", - "followup_date", - "sb_discharge_note", - "discharge_note" - ], - "fields": [ - { - "fieldname": "section_break_1", - "fieldtype": "Section Break" - }, - { - "fieldname": "naming_series", - "fieldtype": "Select", - "hidden": 1, - "label": "Series", - "options": "HLC-INP-.YYYY.-" - }, - { - "fieldname": "patient", - "fieldtype": "Link", - "in_list_view": 1, - "label": "Patient", - "options": "Patient", - "reqd": 1, - "set_only_once": 1 - }, - { - "fetch_from": "patient.patient_name", - "fieldname": "patient_name", - "fieldtype": "Data", - "label": "Patient Name", - "read_only": 1 - }, - { - "fetch_from": "patient.sex", - "fieldname": "gender", - "fieldtype": "Link", - "label": "Gender", - "options": "Gender", - "read_only": 1 - }, - { - "fetch_from": "patient.blood_group", - "fieldname": "blood_group", - "fieldtype": "Select", - "label": "Blood Group", - "options": "\nA Positive\nA Negative\nAB Positive\nAB Negative\nB Positive\nB Negative\nO Positive\nO Negative", - "read_only": 1 - }, - { - "fetch_from": "patient.dob", - "fieldname": "dob", - "fieldtype": "Date", - "label": "Date of birth", - "read_only": 1 - }, - { - "fetch_from": "patient.mobile", - "fieldname": "mobile", - "fieldtype": "Data", - "label": "Mobile", - "read_only": 1 - }, - { - "fetch_from": "patient.email", - "fieldname": "email", - "fieldtype": "Data", - "label": "Email", - "options": "Email", - "read_only": 1 - }, - { - "fetch_from": "patient.phone", - "fieldname": "phone", - "fieldtype": "Data", - "label": "Phone", - "read_only": 1 - }, - { - "fieldname": "medical_department", - "fieldtype": "Link", - "label": "Medical Department", - "options": "Medical Department", - "set_only_once": 1 - }, - { - "fieldname": "primary_practitioner", - "fieldtype": "Link", - "label": "Healthcare Practitioner (Primary)", - "options": "Healthcare Practitioner" - }, - { - "fieldname": "secondary_practitioner", - "fieldtype": "Link", - "label": "Healthcare Practitioner (Secondary)", - "options": "Healthcare Practitioner" - }, - { - "fieldname": "column_break_8", - "fieldtype": "Column Break" - }, - { - "default": "Admission Scheduled", - "fieldname": "status", - "fieldtype": "Select", - "in_list_view": 1, - "label": "Status", - "options": "Admission Scheduled\nAdmitted\nDischarge Scheduled\nDischarged", - "read_only": 1 - }, - { - "default": "Today", - "fieldname": "scheduled_date", - "fieldtype": "Date", - "in_list_view": 1, - "label": "Admission Schedule Date", - "read_only": 1, - "reqd": 1 - }, - { - "fieldname": "admission_ordered_for", - "fieldtype": "Date", - "label": "Admission Ordered For", - "read_only": 1 - }, - { - "fieldname": "admitted_datetime", - "fieldtype": "Datetime", - "in_list_view": 1, - "label": "Admitted Datetime", - "permlevel": 2 - }, - { - "depends_on": "eval:(doc.expected_length_of_stay > 0)", - "fieldname": "expected_length_of_stay", - "fieldtype": "Int", - "label": "Expected Length of Stay", - "set_only_once": 1 - }, - { - "fieldname": "expected_discharge", - "fieldtype": "Date", - "in_list_view": 1, - "label": "Expected Discharge", - "read_only": 1 - }, - { - "collapsible": 1, - "fieldname": "references", - "fieldtype": "Section Break", - "label": "Admission Order Details" - }, - { - "fieldname": "cb_admission", - "fieldtype": "Column Break" - }, - { - "fieldname": "admission_practitioner", - "fieldtype": "Link", - "label": "Healthcare Practitioner", - "options": "Healthcare Practitioner", - "read_only": 1 - }, - { - "fieldname": "admission_encounter", - "fieldtype": "Link", - "label": "Patient Encounter", - "options": "Patient Encounter", - "read_only": 1 - }, - { - "fieldname": "chief_complaint", - "fieldtype": "Table MultiSelect", - "label": "Chief Complaint", - "options": "Patient Encounter Symptom", - "permlevel": 1 - }, - { - "fieldname": "admission_instruction", - "fieldtype": "Small Text", - "label": "Admission Instruction", - "set_only_once": 1 - }, - { - "fieldname": "cb_discharge", - "fieldtype": "Column Break" - }, - { - "fieldname": "discharge_practitioner", - "fieldtype": "Link", - "label": "Healthcare Practitioner", - "options": "Healthcare Practitioner", - "read_only": 1 - }, - { - "fieldname": "discharge_encounter", - "fieldtype": "Link", - "label": "Patient Encounter", - "options": "Patient Encounter", - "read_only": 1 - }, - { - "collapsible": 1, - "fieldname": "medication_section", - "fieldtype": "Section Break", - "label": "Medications", - "permlevel": 1 - }, - { - "fieldname": "drug_prescription", - "fieldtype": "Table", - "options": "Drug Prescription", - "permlevel": 1 - }, - { - "collapsible": 1, - "fieldname": "investigations_section", - "fieldtype": "Section Break", - "label": "Investigations", - "permlevel": 1 - }, - { - "fieldname": "lab_test_prescription", - "fieldtype": "Table", - "options": "Lab Prescription", - "permlevel": 1 - }, - { - "collapsible": 1, - "fieldname": "procedures_section", - "fieldtype": "Section Break", - "label": "Procedures", - "permlevel": 1 - }, - { - "fieldname": "procedure_prescription", - "fieldtype": "Table", - "options": "Procedure Prescription", - "permlevel": 1 - }, - { - "depends_on": "eval:(doc.status != \"Admission Scheduled\")", - "fieldname": "sb_inpatient_occupancy", - "fieldtype": "Section Break", - "label": "Inpatient Occupancy" - }, - { - "fieldname": "admission_service_unit_type", - "fieldtype": "Link", - "label": "Admission Service Unit Type", - "options": "Healthcare Service Unit Type", - "read_only": 1 - }, - { - "fieldname": "inpatient_occupancies", - "fieldtype": "Table", - "options": "Inpatient Occupancy", - "permlevel": 2 - }, - { - "fieldname": "btn_transfer", - "fieldtype": "Button", - "label": "Transfer" - }, - { - "depends_on": "eval:(doc.status == \"Discharge Scheduled\" || doc.status == \"Discharged\")", - "fieldname": "sb_discharge_note", - "fieldtype": "Section Break", - "label": "Discharge Notes" - }, - { - "fieldname": "discharge_note", - "fieldtype": "Text Editor", - "permlevel": 1 - }, - { - "fetch_from": "admission_encounter.company", - "fieldname": "company", - "fieldtype": "Link", - "in_standard_filter": 1, - "label": "Company", - "options": "Company" - }, - { - "collapsible": 1, - "collapsible_depends_on": "eval:(doc.status == \"Admitted\")", - "fieldname": "encounter_details_section", - "fieldtype": "Section Break", - "label": "Encounter Impression", - "permlevel": 1 - }, - { - "fieldname": "column_break_29", - "fieldtype": "Column Break" - }, - { - "fieldname": "diagnosis", - "fieldtype": "Table MultiSelect", - "label": "Diagnosis", - "options": "Patient Encounter Diagnosis", - "permlevel": 1 - }, - { - "fieldname": "followup_date", - "fieldtype": "Date", - "label": "Follow Up Date" - }, - { - "collapsible": 1, - "depends_on": "eval:(doc.status == \"Discharge Scheduled\" || doc.status == \"Discharged\")", - "fieldname": "sb_discharge_details", - "fieldtype": "Section Break", - "label": "Discharge Detials" - }, - { - "fieldname": "discharge_instructions", - "fieldtype": "Small Text", - "label": "Discharge Instructions" - }, - { - "fieldname": "discharge_ordered_date", - "fieldtype": "Date", - "in_list_view": 1, - "label": "Discharge Ordered Date", - "read_only": 1 - }, - { - "collapsible": 1, - "fieldname": "rehabilitation_section", - "fieldtype": "Section Break", - "label": "Rehabilitation", - "permlevel": 1 - }, - { - "fieldname": "therapy_plan", - "fieldtype": "Link", - "hidden": 1, - "label": "Therapy Plan", - "options": "Therapy Plan", - "permlevel": 1, - "read_only": 1 - }, - { - "fieldname": "therapies", - "fieldtype": "Table", - "options": "Therapy Plan Detail", - "permlevel": 1 - }, - { - "fieldname": "discharge_datetime", - "fieldtype": "Datetime", - "label": "Discharge Date", - "permlevel": 2 - } - ], - "index_web_pages_for_search": 1, - "links": [], - "modified": "2021-03-18 15:59:17.318988", - "modified_by": "Administrator", - "module": "Healthcare", - "name": "Inpatient Record", - "owner": "Administrator", - "permissions": [ - { - "create": 1, - "delete": 1, - "email": 1, - "export": 1, - "print": 1, - "read": 1, - "report": 1, - "role": "Healthcare Administrator", - "share": 1, - "write": 1 - }, - { - "create": 1, - "delete": 1, - "email": 1, - "export": 1, - "print": 1, - "read": 1, - "report": 1, - "role": "Physician", - "share": 1, - "write": 1 - }, - { - "create": 1, - "delete": 1, - "email": 1, - "export": 1, - "print": 1, - "read": 1, - "report": 1, - "role": "Nursing User", - "share": 1, - "write": 1 - }, - { - "permlevel": 1, - "read": 1, - "role": "Physician", - "write": 1 - }, - { - "permlevel": 1, - "read": 1, - "report": 1, - "role": "Nursing User" - }, - { - "email": 1, - "export": 1, - "permlevel": 2, - "print": 1, - "read": 1, - "report": 1, - "role": "Healthcare Administrator", - "share": 1, - "write": 1 - }, - { - "email": 1, - "export": 1, - "permlevel": 2, - "print": 1, - "read": 1, - "report": 1, - "role": "Physician", - "share": 1 - }, - { - "email": 1, - "export": 1, - "permlevel": 2, - "print": 1, - "read": 1, - "report": 1, - "role": "Nursing User", - "share": 1 - } - ], - "restrict_to_domain": "Healthcare", - "search_fields": "patient", - "sort_field": "modified", - "sort_order": "DESC", - "title_field": "patient", - "track_changes": 1 -} \ No newline at end of file diff --git a/erpnext/healthcare/doctype/inpatient_record/inpatient_record.py b/erpnext/healthcare/doctype/inpatient_record/inpatient_record.py deleted file mode 100644 index 2e26677db5d..00000000000 --- a/erpnext/healthcare/doctype/inpatient_record/inpatient_record.py +++ /dev/null @@ -1,291 +0,0 @@ -# -*- coding: utf-8 -*- -# Copyright (c) 2018, Frappe Technologies Pvt. Ltd. and contributors -# For license information, please see license.txt - -from __future__ import unicode_literals - -import json - -import frappe -from frappe import _ -from frappe.desk.reportview import get_match_cond -from frappe.model.document import Document -from frappe.utils import get_datetime, get_link_to_form, getdate, now_datetime, today - - -class InpatientRecord(Document): - def after_insert(self): - frappe.db.set_value('Patient', self.patient, 'inpatient_record', self.name) - frappe.db.set_value('Patient', self.patient, 'inpatient_status', self.status) - - if self.admission_encounter: # Update encounter - frappe.db.set_value('Patient Encounter', self.admission_encounter, 'inpatient_record', self.name) - frappe.db.set_value('Patient Encounter', self.admission_encounter, 'inpatient_status', self.status) - - def validate(self): - self.validate_dates() - self.validate_already_scheduled_or_admitted() - if self.status == "Discharged": - frappe.db.set_value("Patient", self.patient, "inpatient_status", None) - frappe.db.set_value("Patient", self.patient, "inpatient_record", None) - - def validate_dates(self): - if (getdate(self.expected_discharge) < getdate(self.scheduled_date)) or \ - (getdate(self.discharge_ordered_date) < getdate(self.scheduled_date)): - frappe.throw(_('Expected and Discharge dates cannot be less than Admission Schedule date')) - - for entry in self.inpatient_occupancies: - if entry.check_in and entry.check_out and \ - get_datetime(entry.check_in) > get_datetime(entry.check_out): - frappe.throw(_('Row #{0}: Check Out datetime cannot be less than Check In datetime').format(entry.idx)) - - def validate_already_scheduled_or_admitted(self): - query = """ - select name, status - from `tabInpatient Record` - where (status = 'Admitted' or status = 'Admission Scheduled') - and name != %(name)s and patient = %(patient)s - """ - - ip_record = frappe.db.sql(query,{ - "name": self.name, - "patient": self.patient - }, as_dict = 1) - - if ip_record: - msg = _(("Already {0} Patient {1} with Inpatient Record ").format(ip_record[0].status, self.patient) \ - + """ {0}""".format(ip_record[0].name)) - frappe.throw(msg) - - @frappe.whitelist() - def admit(self, service_unit, check_in, expected_discharge=None): - admit_patient(self, service_unit, check_in, expected_discharge) - - @frappe.whitelist() - def discharge(self): - discharge_patient(self) - - @frappe.whitelist() - def transfer(self, service_unit, check_in, leave_from): - if leave_from: - patient_leave_service_unit(self, check_in, leave_from) - if service_unit: - transfer_patient(self, service_unit, check_in) - - -@frappe.whitelist() -def schedule_inpatient(args): - admission_order = json.loads(args) # admission order via Encounter - if not admission_order or not admission_order['patient'] or not admission_order['admission_encounter']: - frappe.throw(_('Missing required details, did not create Inpatient Record')) - - inpatient_record = frappe.new_doc('Inpatient Record') - - # Admission order details - set_details_from_ip_order(inpatient_record, admission_order) - - # Patient details - patient = frappe.get_doc('Patient', admission_order['patient']) - inpatient_record.patient = patient.name - inpatient_record.patient_name = patient.patient_name - inpatient_record.gender = patient.sex - inpatient_record.blood_group = patient.blood_group - inpatient_record.dob = patient.dob - inpatient_record.mobile = patient.mobile - inpatient_record.email = patient.email - inpatient_record.phone = patient.phone - inpatient_record.scheduled_date = today() - - # Set encounter detials - encounter = frappe.get_doc('Patient Encounter', admission_order['admission_encounter']) - if encounter and encounter.symptoms: # Symptoms - set_ip_child_records(inpatient_record, 'chief_complaint', encounter.symptoms) - - if encounter and encounter.diagnosis: # Diagnosis - set_ip_child_records(inpatient_record, 'diagnosis', encounter.diagnosis) - - if encounter and encounter.drug_prescription: # Medication - set_ip_child_records(inpatient_record, 'drug_prescription', encounter.drug_prescription) - - if encounter and encounter.lab_test_prescription: # Lab Tests - set_ip_child_records(inpatient_record, 'lab_test_prescription', encounter.lab_test_prescription) - - if encounter and encounter.procedure_prescription: # Procedure Prescription - set_ip_child_records(inpatient_record, 'procedure_prescription', encounter.procedure_prescription) - - if encounter and encounter.therapies: # Therapies - inpatient_record.therapy_plan = encounter.therapy_plan - set_ip_child_records(inpatient_record, 'therapies', encounter.therapies) - - inpatient_record.status = 'Admission Scheduled' - inpatient_record.save(ignore_permissions = True) - - -@frappe.whitelist() -def schedule_discharge(args): - discharge_order = json.loads(args) - inpatient_record_id = frappe.db.get_value('Patient', discharge_order['patient'], 'inpatient_record') - if inpatient_record_id: - inpatient_record = frappe.get_doc('Inpatient Record', inpatient_record_id) - check_out_inpatient(inpatient_record) - set_details_from_ip_order(inpatient_record, discharge_order) - inpatient_record.status = 'Discharge Scheduled' - inpatient_record.save(ignore_permissions = True) - frappe.db.set_value('Patient', discharge_order['patient'], 'inpatient_status', inpatient_record.status) - frappe.db.set_value('Patient Encounter', inpatient_record.discharge_encounter, 'inpatient_status', inpatient_record.status) - - -def set_details_from_ip_order(inpatient_record, ip_order): - for key in ip_order: - inpatient_record.set(key, ip_order[key]) - - -def set_ip_child_records(inpatient_record, inpatient_record_child, encounter_child): - for item in encounter_child: - table = inpatient_record.append(inpatient_record_child) - for df in table.meta.get('fields'): - table.set(df.fieldname, item.get(df.fieldname)) - - -def check_out_inpatient(inpatient_record): - if inpatient_record.inpatient_occupancies: - for inpatient_occupancy in inpatient_record.inpatient_occupancies: - if inpatient_occupancy.left != 1: - inpatient_occupancy.left = True - inpatient_occupancy.check_out = now_datetime() - frappe.db.set_value("Healthcare Service Unit", inpatient_occupancy.service_unit, "occupancy_status", "Vacant") - - -def discharge_patient(inpatient_record): - validate_inpatient_invoicing(inpatient_record) - inpatient_record.discharge_datetime = now_datetime() - inpatient_record.status = "Discharged" - - inpatient_record.save(ignore_permissions = True) - - -def validate_inpatient_invoicing(inpatient_record): - if frappe.db.get_single_value("Healthcare Settings", "allow_discharge_despite_unbilled_services"): - return - - pending_invoices = get_pending_invoices(inpatient_record) - - if pending_invoices: - message = _("Cannot mark Inpatient Record as Discharged since there are unbilled services. ") - - formatted_doc_rows = '' - - for doctype, docnames in pending_invoices.items(): - formatted_doc_rows += """ -

{0}{1}
- - - - - {2} -
{0}{1}
- """.format(_("Healthcare Service"), _("Documents"), formatted_doc_rows) - - frappe.throw(message, title=_("Unbilled Services"), is_minimizable=True, wide=True) - - -def get_pending_invoices(inpatient_record): - pending_invoices = {} - if inpatient_record.inpatient_occupancies: - service_unit_names = False - for inpatient_occupancy in inpatient_record.inpatient_occupancies: - if not inpatient_occupancy.invoiced: - if service_unit_names: - service_unit_names += ", " + inpatient_occupancy.service_unit - else: - service_unit_names = inpatient_occupancy.service_unit - if service_unit_names: - pending_invoices["Inpatient Occupancy"] = service_unit_names - - docs = ["Patient Appointment", "Patient Encounter", "Lab Test", "Clinical Procedure"] - - for doc in docs: - doc_name_list = get_unbilled_inpatient_docs(doc, inpatient_record) - if doc_name_list: - pending_invoices = get_pending_doc(doc, doc_name_list, pending_invoices) - - return pending_invoices - - -def get_pending_doc(doc, doc_name_list, pending_invoices): - if doc_name_list: - doc_ids = False - for doc_name in doc_name_list: - doc_link = get_link_to_form(doc, doc_name.name) - if doc_ids: - doc_ids += ", " + doc_link - else: - doc_ids = doc_link - if doc_ids: - pending_invoices[doc] = doc_ids - - return pending_invoices - - -def get_unbilled_inpatient_docs(doc, inpatient_record): - return frappe.db.get_list(doc, filters = {'patient': inpatient_record.patient, - 'inpatient_record': inpatient_record.name, 'docstatus': 1, 'invoiced': 0}) - - -def admit_patient(inpatient_record, service_unit, check_in, expected_discharge=None): - inpatient_record.admitted_datetime = check_in - inpatient_record.status = 'Admitted' - inpatient_record.expected_discharge = expected_discharge - - inpatient_record.set('inpatient_occupancies', []) - transfer_patient(inpatient_record, service_unit, check_in) - - frappe.db.set_value('Patient', inpatient_record.patient, 'inpatient_status', 'Admitted') - frappe.db.set_value('Patient', inpatient_record.patient, 'inpatient_record', inpatient_record.name) - - -def transfer_patient(inpatient_record, service_unit, check_in): - item_line = inpatient_record.append('inpatient_occupancies', {}) - item_line.service_unit = service_unit - item_line.check_in = check_in - - inpatient_record.save(ignore_permissions = True) - - frappe.db.set_value("Healthcare Service Unit", service_unit, "occupancy_status", "Occupied") - - -def patient_leave_service_unit(inpatient_record, check_out, leave_from): - if inpatient_record.inpatient_occupancies: - for inpatient_occupancy in inpatient_record.inpatient_occupancies: - if inpatient_occupancy.left != 1 and inpatient_occupancy.service_unit == leave_from: - inpatient_occupancy.left = True - inpatient_occupancy.check_out = check_out - frappe.db.set_value("Healthcare Service Unit", inpatient_occupancy.service_unit, "occupancy_status", "Vacant") - inpatient_record.save(ignore_permissions = True) - - -@frappe.whitelist() -@frappe.validate_and_sanitize_search_inputs -def get_leave_from(doctype, txt, searchfield, start, page_len, filters): - docname = filters['docname'] - - query = '''select io.service_unit - from `tabInpatient Occupancy` io, `tabInpatient Record` ir - where io.parent = '{docname}' and io.parentfield = 'inpatient_occupancies' - and io.left!=1 and io.parent = ir.name''' - - return frappe.db.sql(query.format(**{ - "docname": docname, - "searchfield": searchfield, - "mcond": get_match_cond(doctype) - }), { - 'txt': "%%%s%%" % txt, - '_txt': txt.replace("%", ""), - 'start': start, - 'page_len': page_len - }) diff --git a/erpnext/healthcare/doctype/inpatient_record/inpatient_record_dashboard.py b/erpnext/healthcare/doctype/inpatient_record/inpatient_record_dashboard.py deleted file mode 100644 index 0f4adce4edf..00000000000 --- a/erpnext/healthcare/doctype/inpatient_record/inpatient_record_dashboard.py +++ /dev/null @@ -1,19 +0,0 @@ -from __future__ import unicode_literals - -from frappe import _ - - -def get_data(): - return { - 'fieldname': 'inpatient_record', - 'transactions': [ - { - 'label': _('Appointments and Encounters'), - 'items': ['Patient Appointment', 'Patient Encounter'] - }, - { - 'label': _('Lab Tests and Vital Signs'), - 'items': ['Lab Test', 'Clinical Procedure', 'Sample Collection', 'Vital Signs'] - } - ] - } diff --git a/erpnext/healthcare/doctype/inpatient_record/test_inpatient_record.py b/erpnext/healthcare/doctype/inpatient_record/test_inpatient_record.py deleted file mode 100644 index 58934e6a03a..00000000000 --- a/erpnext/healthcare/doctype/inpatient_record/test_inpatient_record.py +++ /dev/null @@ -1,205 +0,0 @@ -# -*- coding: utf-8 -*- -# Copyright (c) 2018, Frappe Technologies Pvt. Ltd. and Contributors -# See license.txt -from __future__ import unicode_literals - -import unittest - -import frappe -from frappe.utils import now_datetime, today -from frappe.utils.make_random import get_random - -from erpnext.healthcare.doctype.inpatient_record.inpatient_record import ( - admit_patient, - discharge_patient, - schedule_discharge, -) -from erpnext.healthcare.doctype.lab_test.test_lab_test import create_patient_encounter -from erpnext.healthcare.utils import get_encounters_to_invoice - - -class TestInpatientRecord(unittest.TestCase): - def test_admit_and_discharge(self): - frappe.db.sql("""delete from `tabInpatient Record`""") - patient = create_patient() - # Schedule Admission - ip_record = create_inpatient(patient) - ip_record.expected_length_of_stay = 0 - ip_record.save(ignore_permissions = True) - self.assertEqual(ip_record.name, frappe.db.get_value("Patient", patient, "inpatient_record")) - self.assertEqual(ip_record.status, frappe.db.get_value("Patient", patient, "inpatient_status")) - - # Admit - service_unit = get_healthcare_service_unit() - admit_patient(ip_record, service_unit, now_datetime()) - self.assertEqual("Admitted", frappe.db.get_value("Patient", patient, "inpatient_status")) - self.assertEqual("Occupied", frappe.db.get_value("Healthcare Service Unit", service_unit, "occupancy_status")) - - # Discharge - schedule_discharge(frappe.as_json({'patient': patient})) - self.assertEqual("Vacant", frappe.db.get_value("Healthcare Service Unit", service_unit, "occupancy_status")) - - ip_record1 = frappe.get_doc("Inpatient Record", ip_record.name) - # Validate Pending Invoices - self.assertRaises(frappe.ValidationError, ip_record.discharge) - mark_invoiced_inpatient_occupancy(ip_record1) - - discharge_patient(ip_record1) - - self.assertEqual(None, frappe.db.get_value("Patient", patient, "inpatient_record")) - self.assertEqual(None, frappe.db.get_value("Patient", patient, "inpatient_status")) - - def test_allow_discharge_despite_unbilled_services(self): - frappe.db.sql("""delete from `tabInpatient Record`""") - setup_inpatient_settings(key="allow_discharge_despite_unbilled_services", value=1) - patient = create_patient() - # Schedule Admission - ip_record = create_inpatient(patient) - ip_record.expected_length_of_stay = 0 - ip_record.save(ignore_permissions = True) - - # Admit - service_unit = get_healthcare_service_unit() - admit_patient(ip_record, service_unit, now_datetime()) - - # Discharge - schedule_discharge(frappe.as_json({"patient": patient})) - self.assertEqual("Vacant", frappe.db.get_value("Healthcare Service Unit", service_unit, "occupancy_status")) - - ip_record = frappe.get_doc("Inpatient Record", ip_record.name) - # Should not validate Pending Invoices - ip_record.discharge() - - self.assertEqual(None, frappe.db.get_value("Patient", patient, "inpatient_record")) - self.assertEqual(None, frappe.db.get_value("Patient", patient, "inpatient_status")) - - setup_inpatient_settings(key="allow_discharge_despite_unbilled_services", value=0) - - def test_do_not_bill_patient_encounters_for_inpatients(self): - frappe.db.sql("""delete from `tabInpatient Record`""") - setup_inpatient_settings(key="do_not_bill_inpatient_encounters", value=1) - patient = create_patient() - # Schedule Admission - ip_record = create_inpatient(patient) - ip_record.expected_length_of_stay = 0 - ip_record.save(ignore_permissions = True) - - # Admit - service_unit = get_healthcare_service_unit() - admit_patient(ip_record, service_unit, now_datetime()) - - # Patient Encounter - patient_encounter = create_patient_encounter() - encounters = get_encounters_to_invoice(patient, "_Test Company") - encounter_ids = [entry.reference_name for entry in encounters] - self.assertFalse(patient_encounter.name in encounter_ids) - - # Discharge - schedule_discharge(frappe.as_json({"patient": patient})) - self.assertEqual("Vacant", frappe.db.get_value("Healthcare Service Unit", service_unit, "occupancy_status")) - - ip_record = frappe.get_doc("Inpatient Record", ip_record.name) - mark_invoiced_inpatient_occupancy(ip_record) - discharge_patient(ip_record) - setup_inpatient_settings(key="do_not_bill_inpatient_encounters", value=0) - - def test_validate_overlap_admission(self): - frappe.db.sql("""delete from `tabInpatient Record`""") - patient = create_patient() - - ip_record = create_inpatient(patient) - ip_record.expected_length_of_stay = 0 - ip_record.save(ignore_permissions = True) - ip_record_new = create_inpatient(patient) - ip_record_new.expected_length_of_stay = 0 - self.assertRaises(frappe.ValidationError, ip_record_new.save) - - service_unit = get_healthcare_service_unit() - admit_patient(ip_record, service_unit, now_datetime()) - ip_record_new = create_inpatient(patient) - self.assertRaises(frappe.ValidationError, ip_record_new.save) - frappe.db.sql("""delete from `tabInpatient Record`""") - -def mark_invoiced_inpatient_occupancy(ip_record): - if ip_record.inpatient_occupancies: - for inpatient_occupancy in ip_record.inpatient_occupancies: - inpatient_occupancy.invoiced = 1 - ip_record.save(ignore_permissions = True) - - -def setup_inpatient_settings(key, value): - settings = frappe.get_single("Healthcare Settings") - settings.set(key, value) - settings.save() - - -def create_inpatient(patient): - patient_obj = frappe.get_doc('Patient', patient) - inpatient_record = frappe.new_doc('Inpatient Record') - inpatient_record.patient = patient - inpatient_record.patient_name = patient_obj.patient_name - inpatient_record.gender = patient_obj.sex - inpatient_record.blood_group = patient_obj.blood_group - inpatient_record.dob = patient_obj.dob - inpatient_record.mobile = patient_obj.mobile - inpatient_record.email = patient_obj.email - inpatient_record.phone = patient_obj.phone - inpatient_record.inpatient = "Scheduled" - inpatient_record.scheduled_date = today() - inpatient_record.company = "_Test Company" - return inpatient_record - - -def get_healthcare_service_unit(unit_name=None): - if not unit_name: - service_unit = get_random("Healthcare Service Unit", filters={"inpatient_occupancy": 1, "company": "_Test Company"}) - else: - service_unit = frappe.db.exists("Healthcare Service Unit", {"healthcare_service_unit_name": unit_name}) - - if not service_unit: - service_unit = frappe.new_doc("Healthcare Service Unit") - service_unit.healthcare_service_unit_name = unit_name or "_Test Service Unit Ip Occupancy" - service_unit.company = "_Test Company" - service_unit.service_unit_type = get_service_unit_type() - service_unit.inpatient_occupancy = 1 - service_unit.occupancy_status = "Vacant" - service_unit.is_group = 0 - service_unit_parent_name = frappe.db.exists({ - "doctype": "Healthcare Service Unit", - "healthcare_service_unit_name": "_Test All Healthcare Service Units", - "is_group": 1 - }) - if not service_unit_parent_name: - parent_service_unit = frappe.new_doc("Healthcare Service Unit") - parent_service_unit.healthcare_service_unit_name = "_Test All Healthcare Service Units" - parent_service_unit.is_group = 1 - parent_service_unit.save(ignore_permissions = True) - service_unit.parent_healthcare_service_unit = parent_service_unit.name - else: - service_unit.parent_healthcare_service_unit = service_unit_parent_name[0][0] - service_unit.save(ignore_permissions = True) - return service_unit.name - return service_unit - - -def get_service_unit_type(): - service_unit_type = get_random("Healthcare Service Unit Type", filters={"inpatient_occupancy": 1}) - - if not service_unit_type: - service_unit_type = frappe.new_doc("Healthcare Service Unit Type") - service_unit_type.service_unit_type = "_Test Service Unit Type Ip Occupancy" - service_unit_type.inpatient_occupancy = 1 - service_unit_type.save(ignore_permissions = True) - return service_unit_type.name - return service_unit_type - - -def create_patient(): - patient = frappe.db.exists('Patient', '_Test IPD Patient') - if not patient: - patient = frappe.new_doc('Patient') - patient.first_name = '_Test IPD Patient' - patient.sex = 'Female' - patient.save(ignore_permissions=True) - patient = patient.name - return patient diff --git a/erpnext/healthcare/doctype/lab_prescription/__init__.py b/erpnext/healthcare/doctype/lab_prescription/__init__.py deleted file mode 100644 index e69de29bb2d..00000000000 diff --git a/erpnext/healthcare/doctype/lab_prescription/lab_prescription.json b/erpnext/healthcare/doctype/lab_prescription/lab_prescription.json deleted file mode 100644 index 0720bb4eecd..00000000000 --- a/erpnext/healthcare/doctype/lab_prescription/lab_prescription.json +++ /dev/null @@ -1,78 +0,0 @@ -{ - "actions": [], - "allow_copy": 1, - "beta": 1, - "creation": "2016-09-16 16:53:06.882970", - "doctype": "DocType", - "document_type": "Document", - "editable_grid": 1, - "engine": "InnoDB", - "field_order": [ - "lab_test_code", - "lab_test_name", - "invoiced", - "column_break_4", - "lab_test_comment", - "lab_test_created" - ], - "fields": [ - { - "fieldname": "lab_test_code", - "fieldtype": "Link", - "ignore_user_permissions": 1, - "in_list_view": 1, - "label": "Lab Test", - "options": "Lab Test Template", - "reqd": 1 - }, - { - "fetch_from": "lab_test_code.lab_test_name", - "fieldname": "lab_test_name", - "fieldtype": "Data", - "in_list_view": 1, - "label": "Lab Test Name" - }, - { - "default": "0", - "fieldname": "invoiced", - "fieldtype": "Check", - "label": "Invoiced", - "no_copy": 1, - "read_only": 1, - "search_index": 1 - }, - { - "fieldname": "column_break_4", - "fieldtype": "Column Break" - }, - { - "fieldname": "lab_test_comment", - "fieldtype": "Small Text", - "ignore_xss_filter": 1, - "in_list_view": 1, - "label": "Comments" - }, - { - "default": "0", - "fieldname": "lab_test_created", - "fieldtype": "Check", - "hidden": 1, - "label": "Test Created", - "no_copy": 1, - "print_hide": 1, - "report_hide": 1, - "search_index": 1 - } - ], - "istable": 1, - "links": [], - "modified": "2020-02-26 17:03:00.255560", - "modified_by": "Administrator", - "module": "Healthcare", - "name": "Lab Prescription", - "owner": "Administrator", - "permissions": [], - "restrict_to_domain": "Healthcare", - "sort_field": "modified", - "sort_order": "DESC" -} \ No newline at end of file diff --git a/erpnext/healthcare/doctype/lab_prescription/lab_prescription.py b/erpnext/healthcare/doctype/lab_prescription/lab_prescription.py deleted file mode 100644 index a3f9aa24c48..00000000000 --- a/erpnext/healthcare/doctype/lab_prescription/lab_prescription.py +++ /dev/null @@ -1,11 +0,0 @@ -# -*- coding: utf-8 -*- -# Copyright (c) 2015, ESS LLP and contributors -# For license information, please see license.txt - -from __future__ import unicode_literals - -from frappe.model.document import Document - - -class LabPrescription(Document): - pass diff --git a/erpnext/healthcare/doctype/lab_test/__init__.py b/erpnext/healthcare/doctype/lab_test/__init__.py deleted file mode 100644 index e69de29bb2d..00000000000 diff --git a/erpnext/healthcare/doctype/lab_test/lab_test.js b/erpnext/healthcare/doctype/lab_test/lab_test.js deleted file mode 100644 index bb7976ccfac..00000000000 --- a/erpnext/healthcare/doctype/lab_test/lab_test.js +++ /dev/null @@ -1,262 +0,0 @@ -// Copyright (c) 2016, ESS and contributors -// For license information, please see license.txt - -cur_frm.cscript.custom_refresh = function (doc) { - cur_frm.toggle_display('sb_sensitivity', doc.sensitivity_toggle); - cur_frm.toggle_display('organisms_section', doc.descriptive_toggle); - cur_frm.toggle_display('sb_descriptive', doc.descriptive_toggle); - cur_frm.toggle_display('sb_normal', doc.normal_toggle); -}; - -frappe.ui.form.on('Lab Test', { - setup: function (frm) { - frm.get_field('normal_test_items').grid.editable_fields = [ - { fieldname: 'lab_test_name', columns: 3 }, - { fieldname: 'lab_test_event', columns: 2 }, - { fieldname: 'result_value', columns: 2 }, - { fieldname: 'lab_test_uom', columns: 1 }, - { fieldname: 'normal_range', columns: 2 } - ]; - frm.get_field('descriptive_test_items').grid.editable_fields = [ - { fieldname: 'lab_test_particulars', columns: 3 }, - { fieldname: 'result_value', columns: 7 } - ]; - }, - refresh: function (frm) { - refresh_field('normal_test_items'); - refresh_field('descriptive_test_items'); - if (frm.doc.__islocal) { - frm.add_custom_button(__('Get from Patient Encounter'), function () { - get_lab_test_prescribed(frm); - }); - } - if (frappe.defaults.get_default('lab_test_approval_required') && frappe.user.has_role('LabTest Approver')) { - if (frm.doc.docstatus === 1 && frm.doc.status !== 'Approved' && frm.doc.status !== 'Rejected') { - frm.add_custom_button(__('Approve'), function () { - status_update(1, frm); - }, __('Actions')); - frm.add_custom_button(__('Reject'), function () { - status_update(0, frm); - }, __('Actions')); - } - } - - if (frm.doc.docstatus === 1 && frm.doc.sms_sent === 0 && frm.doc.status !== 'Rejected' ) { - frm.add_custom_button(__('Send SMS'), function () { - frappe.call({ - method: 'erpnext.healthcare.doctype.healthcare_settings.healthcare_settings.get_sms_text', - args: { doc: frm.doc.name }, - callback: function (r) { - if (!r.exc) { - var emailed = r.message.emailed; - var printed = r.message.printed; - make_dialog(frm, emailed, printed); - } - } - }); - }); - } - - } -}); - -frappe.ui.form.on('Lab Test', 'patient', function (frm) { - if (frm.doc.patient) { - frappe.call({ - 'method': 'erpnext.healthcare.doctype.patient.patient.get_patient_detail', - args: { patient: frm.doc.patient }, - callback: function (data) { - var age = null; - if (data.message.dob) { - age = calculate_age(data.message.dob); - } - let values = { - 'patient_age': age, - 'patient_sex': data.message.sex, - 'email': data.message.email, - 'mobile': data.message.mobile, - 'report_preference': data.message.report_preference - }; - frm.set_value(values); - } - }); - } -}); - -frappe.ui.form.on('Normal Test Result', { - normal_test_items_remove: function () { - frappe.msgprint(__('Not permitted, configure Lab Test Template as required')); - cur_frm.reload_doc(); - } -}); - -frappe.ui.form.on('Descriptive Test Result', { - descriptive_test_items_remove: function () { - frappe.msgprint(__('Not permitted, configure Lab Test Template as required')); - cur_frm.reload_doc(); - } -}); - -var status_update = function (approve, frm) { - var doc = frm.doc; - var status = null; - if (approve == 1) { - status = 'Approved'; - } - else { - status = 'Rejected'; - } - frappe.call({ - method: 'erpnext.healthcare.doctype.lab_test.lab_test.update_status', - args: { status: status, name: doc.name }, - callback: function () { - cur_frm.reload_doc(); - } - }); -}; - -var get_lab_test_prescribed = function (frm) { - if (frm.doc.patient) { - frappe.call({ - method: 'erpnext.healthcare.doctype.lab_test.lab_test.get_lab_test_prescribed', - args: { patient: frm.doc.patient }, - callback: function (r) { - show_lab_tests(frm, r.message); - } - }); - } - else { - frappe.msgprint(__('Please select Patient to get Lab Tests')); - } -}; - -var show_lab_tests = function (frm, lab_test_list) { - var d = new frappe.ui.Dialog({ - title: __('Lab Tests'), - fields: [{ - fieldtype: 'HTML', fieldname: 'lab_test' - }] - }); - var html_field = d.fields_dict.lab_test.$wrapper; - html_field.empty(); - $.each(lab_test_list, function (x, y) { - var row = $(repl( - '

\ -
%(lab_test)s
\ -
%(practitioner_name)s
%(encounter)s
\ -
%(date)s
\ -
\ - \ -
\ -

', - { name: y[0], lab_test: y[1], encounter: y[2], invoiced: y[3], practitioner: y[4], practitioner_name: y[5], date: y[6] }) - ).appendTo(html_field); - - row.find("a").click(function () { - frm.doc.template = $(this).attr('data-lab-test'); - frm.doc.prescription = $(this).attr('data-name'); - frm.doc.practitioner = $(this).attr('data-practitioner'); - frm.set_df_property('template', 'read_only', 1); - frm.set_df_property('patient', 'read_only', 1); - frm.set_df_property('practitioner', 'read_only', 1); - frm.doc.invoiced = 0; - if ($(this).attr('data-invoiced') === 1) { - frm.doc.invoiced = 1; - } - refresh_field('invoiced'); - refresh_field('template'); - d.hide(); - return false; - }); - }); - if (!lab_test_list.length) { - var msg = __('No Lab Tests found for the Patient {0}', [frm.doc.patient_name.bold()]); - html_field.empty(); - $(repl('
%(msg)s
', { msg: msg })).appendTo(html_field); - } - d.show(); -}; - -var make_dialog = function (frm, emailed, printed) { - var number = frm.doc.mobile; - - var dialog = new frappe.ui.Dialog({ - title: 'Send SMS', - width: 400, - fields: [ - { fieldname: 'result_format', fieldtype: 'Select', label: 'Result Format', options: ['Emailed', 'Printed'] }, - { fieldname: 'number', fieldtype: 'Data', label: 'Mobile Number', reqd: 1 }, - { fieldname: 'message', fieldtype: 'Small Text', label: 'Message', reqd: 1 } - ], - primary_action_label: __('Send'), - primary_action: function () { - var values = dialog.fields_dict; - if (!values) { - return; - } - send_sms(values, frm); - dialog.hide(); - } - }); - if (frm.doc.report_preference === 'Print') { - dialog.set_values({ - 'result_format': 'Printed', - 'number': number, - 'message': printed - }); - } else { - dialog.set_values({ - 'result_format': 'Emailed', - 'number': number, - 'message': emailed - }); - } - var fd = dialog.fields_dict; - $(fd.result_format.input).change(function () { - if (dialog.get_value('result_format') === 'Emailed') { - dialog.set_values({ - 'number': number, - 'message': emailed - }); - } else { - dialog.set_values({ - 'number': number, - 'message': printed - }); - } - }); - dialog.show(); -}; - -var send_sms = function (vals, frm) { - var number = vals.number.value; - var message = vals.message.last_value; - - if (!number || !message) { - frappe.throw(__('Did not send SMS, missing patient mobile number or message content.')); - } - frappe.call({ - method: 'frappe.core.doctype.sms_settings.sms_settings.send_sms', - args: { - receiver_list: [number], - msg: message - }, - callback: function (r) { - if (r.exc) { - frappe.msgprint(r.exc); - } else { - frm.reload_doc(); - } - } - }); -}; - -var calculate_age = function (dob) { - var ageMS = Date.parse(Date()) - Date.parse(dob); - var age = new Date(); - age.setTime(ageMS); - var years = age.getFullYear() - 1970; - return `${years} ${__('Years(s)')} ${age.getMonth()} ${__('Month(s)')} ${age.getDate()} ${__('Day(s)')}`; -}; diff --git a/erpnext/healthcare/doctype/lab_test/lab_test.json b/erpnext/healthcare/doctype/lab_test/lab_test.json deleted file mode 100644 index ac61fea3ad7..00000000000 --- a/erpnext/healthcare/doctype/lab_test/lab_test.json +++ /dev/null @@ -1,610 +0,0 @@ -{ - "actions": [], - "allow_copy": 1, - "allow_import": 1, - "autoname": "naming_series:", - "beta": 1, - "creation": "2016-03-29 17:34:47.509094", - "doctype": "DocType", - "document_type": "Document", - "engine": "InnoDB", - "field_order": [ - "naming_series", - "template", - "lab_test_name", - "lab_test_group", - "medical_code", - "department", - "column_break_26", - "company", - "status", - "submitted_date", - "result_date", - "approved_date", - "expected_result_date", - "expected_result_time", - "printed_on", - "invoiced", - "sb_first", - "patient", - "patient_name", - "patient_age", - "patient_sex", - "inpatient_record", - "report_preference", - "email", - "mobile", - "c_b", - "practitioner", - "practitioner_name", - "requesting_department", - "employee", - "employee_name", - "employee_designation", - "user", - "sample", - "sb_normal", - "lab_test_html", - "normal_test_items", - "sb_descriptive", - "descriptive_test_items", - "organisms_section", - "organism_test_items", - "sb_sensitivity", - "sensitivity_test_items", - "sb_comments", - "lab_test_comment", - "sb_customresult", - "custom_result", - "worksheet_section", - "worksheet_instructions", - "result_legend_section", - "legend_print_position", - "result_legend", - "section_break_50", - "email_sent", - "sms_sent", - "printed", - "normal_toggle", - "descriptive_toggle", - "sensitivity_toggle", - "amended_from", - "prescription" - ], - "fields": [ - { - "fetch_from": "patient.inpatient_record", - "fieldname": "inpatient_record", - "fieldtype": "Link", - "label": "Inpatient Record", - "options": "Inpatient Record", - "read_only": 1 - }, - { - "fieldname": "naming_series", - "fieldtype": "Select", - "label": "Series", - "options": "HLC-LAB-.YYYY.-", - "print_hide": 1, - "report_hide": 1, - "reqd": 1 - }, - { - "default": "0", - "fieldname": "invoiced", - "fieldtype": "Check", - "label": "Invoiced", - "no_copy": 1, - "read_only": 1, - "search_index": 1 - }, - { - "fetch_from": "inpatient_record.patient", - "fieldname": "patient", - "fieldtype": "Link", - "ignore_user_permissions": 1, - "in_standard_filter": 1, - "label": "Patient", - "options": "Patient", - "reqd": 1, - "search_index": 1, - "set_only_once": 1 - }, - { - "fetch_from": "patient.patient_name", - "fieldname": "patient_name", - "fieldtype": "Data", - "label": "Patient Name", - "print_hide": 1, - "read_only": 1, - "report_hide": 1 - }, - { - "fieldname": "patient_age", - "fieldtype": "Data", - "label": "Age", - "print_hide": 1, - "read_only": 1, - "report_hide": 1 - }, - { - "fieldname": "patient_sex", - "fieldtype": "Link", - "label": "Gender", - "options": "Gender", - "print_hide": 1, - "read_only": 1, - "report_hide": 1, - "reqd": 1, - "set_only_once": 1 - }, - { - "fieldname": "practitioner", - "fieldtype": "Link", - "ignore_user_permissions": 1, - "in_list_view": 1, - "label": "Requesting Practitioner", - "no_copy": 1, - "options": "Healthcare Practitioner", - "search_index": 1 - }, - { - "fetch_from": "patient.email", - "fieldname": "email", - "fieldtype": "Data", - "hidden": 1, - "label": "Email", - "print_hide": 1, - "read_only": 1, - "report_hide": 1 - }, - { - "fetch_from": "patient.mobile", - "fieldname": "mobile", - "fieldtype": "Data", - "hidden": 1, - "label": "Mobile", - "print_hide": 1, - "read_only": 1, - "report_hide": 1, - "search_index": 1 - }, - { - "fieldname": "company", - "fieldtype": "Link", - "in_standard_filter": 1, - "label": "Company", - "options": "Company", - "print_hide": 1, - "report_hide": 1 - }, - { - "fieldname": "c_b", - "fieldtype": "Column Break", - "print_hide": 1 - }, - { - "fetch_from": "template.department", - "fieldname": "department", - "fieldtype": "Link", - "ignore_user_permissions": 1, - "in_standard_filter": 1, - "label": "Department", - "options": "Medical Department", - "read_only": 1, - "search_index": 1 - }, - { - "fieldname": "status", - "fieldtype": "Select", - "in_list_view": 1, - "label": "Status", - "options": "Draft\nCompleted\nApproved\nRejected\nCancelled", - "read_only": 1, - "search_index": 1 - }, - { - "fieldname": "submitted_date", - "fieldtype": "Datetime", - "hidden": 1, - "label": "Submitted Date", - "print_hide": 1, - "report_hide": 1 - }, - { - "fieldname": "approved_date", - "fieldtype": "Datetime", - "hidden": 1, - "label": "Approved Date", - "print_hide": 1, - "report_hide": 1 - }, - { - "fieldname": "sample", - "fieldtype": "Link", - "ignore_user_permissions": 1, - "in_filter": 1, - "label": "Sample ID", - "options": "Sample Collection", - "print_hide": 1, - "read_only": 1, - "report_hide": 1 - }, - { - "default": "Today", - "fieldname": "expected_result_date", - "fieldtype": "Date", - "hidden": 1, - "label": "Expected Result Date", - "read_only": 1 - }, - { - "fieldname": "expected_result_time", - "fieldtype": "Time", - "hidden": 1, - "label": "Expected Result Time", - "read_only": 1 - }, - { - "fieldname": "result_date", - "fieldtype": "Date", - "label": "Result Date", - "read_only": 1, - "search_index": 1 - }, - { - "allow_on_submit": 1, - "fieldname": "printed_on", - "fieldtype": "Datetime", - "label": "Printed on", - "read_only": 1 - }, - { - "fieldname": "employee", - "fieldtype": "Link", - "label": "Employee (Lab Technician)", - "no_copy": 1, - "options": "Employee", - "print_hide": 1, - "report_hide": 1 - }, - { - "fetch_from": "employee.employee_name", - "fieldname": "employee_name", - "fieldtype": "Data", - "label": "Lab Technician Name", - "no_copy": 1, - "print_hide": 1, - "read_only": 1, - "report_hide": 1 - }, - { - "fetch_from": "employee.designation", - "fieldname": "employee_designation", - "fieldtype": "Data", - "label": "Lab Technician Designation", - "no_copy": 1, - "print_hide": 1, - "read_only": 1, - "report_hide": 1 - }, - { - "fieldname": "user", - "fieldtype": "Link", - "hidden": 1, - "label": "User", - "no_copy": 1, - "options": "User", - "print_hide": 1, - "report_hide": 1 - }, - { - "fetch_from": "patient.report_preference", - "fieldname": "report_preference", - "fieldtype": "Data", - "label": "Report Preference", - "print_hide": 1, - "read_only": 1, - "report_hide": 1 - }, - { - "fieldname": "sb_first", - "fieldtype": "Section Break" - }, - { - "fieldname": "lab_test_name", - "fieldtype": "Data", - "in_list_view": 1, - "label": "Test Name", - "no_copy": 1, - "print_hide": 1, - "read_only": 1, - "report_hide": 1, - "search_index": 1 - }, - { - "fieldname": "template", - "fieldtype": "Link", - "ignore_user_permissions": 1, - "in_standard_filter": 1, - "label": "Test Template", - "options": "Lab Test Template", - "print_hide": 1, - "report_hide": 1, - "reqd": 1, - "set_only_once": 1 - }, - { - "fieldname": "lab_test_group", - "fieldtype": "Link", - "hidden": 1, - "label": "Test Group", - "options": "Item Group", - "print_hide": 1, - "report_hide": 1 - }, - { - "fetch_from": "template.medical_code", - "fieldname": "medical_code", - "fieldtype": "Link", - "label": "Medical Code", - "options": "Medical Code", - "read_only": 1 - }, - { - "fieldname": "sb_normal", - "fieldtype": "Section Break", - "label": "Compound Test Result" - }, - { - "fieldname": "normal_test_items", - "fieldtype": "Table", - "label": "Normal Test Result", - "options": "Normal Test Result", - "print_hide": 1 - }, - { - "fieldname": "lab_test_html", - "fieldtype": "HTML" - }, - { - "depends_on": "descriptive_toggle", - "fieldname": "organisms_section", - "fieldtype": "Section Break", - "label": "Organism Test Result" - }, - { - "fieldname": "sb_sensitivity", - "fieldtype": "Section Break", - "label": "Sensitivity Test Result" - }, - { - "fieldname": "sensitivity_test_items", - "fieldtype": "Table", - "label": "Sensitivity Test Result", - "options": "Sensitivity Test Result", - "print_hide": 1, - "report_hide": 1 - }, - { - "collapsible": 1, - "fieldname": "sb_comments", - "fieldtype": "Section Break", - "label": "Comments" - }, - { - "fieldname": "lab_test_comment", - "fieldtype": "Text", - "ignore_xss_filter": 1, - "label": "Comments", - "print_hide": 1 - }, - { - "collapsible": 1, - "fieldname": "sb_customresult", - "fieldtype": "Section Break", - "label": "Custom Result" - }, - { - "fieldname": "custom_result", - "fieldtype": "Text Editor", - "ignore_xss_filter": 1, - "label": "Custom Result", - "print_hide": 1 - }, - { - "default": "0", - "fieldname": "email_sent", - "fieldtype": "Check", - "hidden": 1, - "print_hide": 1, - "report_hide": 1 - }, - { - "default": "0", - "fieldname": "sms_sent", - "fieldtype": "Check", - "hidden": 1, - "print_hide": 1, - "report_hide": 1 - }, - { - "default": "0", - "fieldname": "printed", - "fieldtype": "Check", - "hidden": 1, - "print_hide": 1, - "report_hide": 1 - }, - { - "default": "0", - "fieldname": "normal_toggle", - "fieldtype": "Check", - "hidden": 1, - "print_hide": 1, - "report_hide": 1 - }, - { - "default": "0", - "fieldname": "sensitivity_toggle", - "fieldtype": "Check", - "hidden": 1, - "print_hide": 1, - "report_hide": 1 - }, - { - "fieldname": "amended_from", - "fieldtype": "Link", - "label": "Amended From", - "no_copy": 1, - "options": "Lab Test", - "print_hide": 1, - "read_only": 1, - "report_hide": 1 - }, - { - "fieldname": "prescription", - "fieldtype": "Link", - "hidden": 1, - "label": "Prescription", - "no_copy": 1, - "options": "Lab Prescription", - "print_hide": 1, - "read_only": 1, - "report_hide": 1 - }, - { - "fieldname": "column_break_26", - "fieldtype": "Column Break" - }, - { - "fetch_from": "practitioner.department", - "fieldname": "requesting_department", - "fieldtype": "Link", - "in_list_view": 1, - "label": "Requesting Department", - "options": "Medical Department", - "read_only": 1 - }, - { - "fetch_from": "practitioner.practitioner_name", - "fieldname": "practitioner_name", - "fieldtype": "Data", - "label": "Requesting Practitioner", - "read_only": 1 - }, - { - "collapsible": 1, - "fieldname": "result_legend_section", - "fieldtype": "Section Break", - "label": "Result Legend Print" - }, - { - "fieldname": "legend_print_position", - "fieldtype": "Select", - "label": "Print Position", - "options": "\nBottom\nTop\nBoth", - "print_hide": 1 - }, - { - "fieldname": "result_legend", - "fieldtype": "Text Editor", - "label": "Result Legend", - "print_hide": 1 - }, - { - "fieldname": "section_break_50", - "fieldtype": "Section Break" - }, - { - "fieldname": "worksheet_instructions", - "fieldtype": "Text Editor", - "label": "Worksheet Instructions", - "print_hide": 1 - }, - { - "collapsible": 1, - "fieldname": "worksheet_section", - "fieldtype": "Section Break", - "label": "Worksheet Print" - }, - { - "fieldname": "descriptive_test_items", - "fieldtype": "Table", - "label": "Descriptive Test Result", - "options": "Descriptive Test Result", - "print_hide": 1, - "report_hide": 1 - }, - { - "fieldname": "sb_descriptive", - "fieldtype": "Section Break", - "label": "Descriptive Test Result" - }, - { - "default": "0", - "fieldname": "descriptive_toggle", - "fieldtype": "Check", - "hidden": 1, - "print_hide": 1, - "report_hide": 1 - }, - { - "fieldname": "organism_test_items", - "fieldtype": "Table", - "label": "Organism Test Result", - "options": "Organism Test Result", - "print_hide": 1 - } - ], - "is_submittable": 1, - "links": [], - "modified": "2020-11-30 11:04:17.195848", - "modified_by": "Administrator", - "module": "Healthcare", - "name": "Lab Test", - "owner": "Administrator", - "permissions": [ - { - "amend": 1, - "cancel": 1, - "create": 1, - "email": 1, - "print": 1, - "read": 1, - "report": 1, - "role": "Laboratory User", - "share": 1, - "submit": 1, - "write": 1 - }, - { - "email": 1, - "export": 1, - "print": 1, - "read": 1, - "report": 1, - "role": "LabTest Approver", - "share": 1, - "write": 1 - }, - { - "email": 1, - "export": 1, - "print": 1, - "read": 1, - "report": 1, - "role": "Physician", - "share": 1, - "write": 1 - } - ], - "restrict_to_domain": "Healthcare", - "search_fields": "patient,practitioner,lab_test_name,sample", - "show_name_in_global_search": 1, - "sort_field": "modified", - "sort_order": "DESC", - "title_field": "patient", - "track_changes": 1, - "track_seen": 1 -} \ No newline at end of file diff --git a/erpnext/healthcare/doctype/lab_test/lab_test.py b/erpnext/healthcare/doctype/lab_test/lab_test.py deleted file mode 100644 index 7db497c24d7..00000000000 --- a/erpnext/healthcare/doctype/lab_test/lab_test.py +++ /dev/null @@ -1,352 +0,0 @@ -# -*- coding: utf-8 -*- -# Copyright (c) 2015, ESS and contributors -# For license information, please see license.txt - -from __future__ import unicode_literals - -import frappe -from frappe import _ -from frappe.model.document import Document -from frappe.utils import get_link_to_form, getdate - - -class LabTest(Document): - def validate(self): - if not self.is_new(): - self.set_secondary_uom_result() - - def on_submit(self): - self.validate_result_values() - self.db_set('submitted_date', getdate()) - self.db_set('status', 'Completed') - - def on_cancel(self): - self.db_set('status', 'Cancelled') - self.reload() - - def on_update(self): - if self.sensitivity_test_items: - sensitivity = sorted(self.sensitivity_test_items, key=lambda x: x.antibiotic_sensitivity) - for i, item in enumerate(sensitivity): - item.idx = i + 1 - self.sensitivity_test_items = sensitivity - - def after_insert(self): - if self.prescription: - frappe.db.set_value('Lab Prescription', self.prescription, 'lab_test_created', 1) - if frappe.db.get_value('Lab Prescription', self.prescription, 'invoiced'): - self.invoiced = True - if self.template: - self.load_test_from_template() - self.reload() - - def load_test_from_template(self): - lab_test = self - create_test_from_template(lab_test) - self.reload() - - def set_secondary_uom_result(self): - for item in self.normal_test_items: - if item.result_value and item.secondary_uom and item.conversion_factor: - try: - item.secondary_uom_result = float(item.result_value) * float(item.conversion_factor) - except Exception: - item.secondary_uom_result = '' - frappe.msgprint(_('Row #{0}: Result for Secondary UOM not calculated').format(item.idx), title = _('Warning')) - - def validate_result_values(self): - if self.normal_test_items: - for item in self.normal_test_items: - if not item.result_value and not item.allow_blank and item.require_result_value: - frappe.throw(_('Row #{0}: Please enter the result value for {1}').format( - item.idx, frappe.bold(item.lab_test_name)), title=_('Mandatory Results')) - - if self.descriptive_test_items: - for item in self.descriptive_test_items: - if not item.result_value and not item.allow_blank and item.require_result_value: - frappe.throw(_('Row #{0}: Please enter the result value for {1}').format( - item.idx, frappe.bold(item.lab_test_particulars)), title=_('Mandatory Results')) - - -def create_test_from_template(lab_test): - template = frappe.get_doc('Lab Test Template', lab_test.template) - patient = frappe.get_doc('Patient', lab_test.patient) - - lab_test.lab_test_name = template.lab_test_name - lab_test.result_date = getdate() - lab_test.department = template.department - lab_test.lab_test_group = template.lab_test_group - lab_test.legend_print_position = template.legend_print_position - lab_test.result_legend = template.result_legend - lab_test.worksheet_instructions = template.worksheet_instructions - - lab_test = create_sample_collection(lab_test, template, patient, None) - lab_test = load_result_format(lab_test, template, None, None) - -@frappe.whitelist() -def update_status(status, name): - if name and status: - frappe.db.set_value('Lab Test', name, { - 'status': status, - 'approved_date': getdate() - }) - -@frappe.whitelist() -def create_multiple(doctype, docname): - if not doctype or not docname: - frappe.throw(_('Sales Invoice or Patient Encounter is required to create Lab Tests'), title=_('Insufficient Data')) - - lab_test_created = False - if doctype == 'Sales Invoice': - lab_test_created = create_lab_test_from_invoice(docname) - elif doctype == 'Patient Encounter': - lab_test_created = create_lab_test_from_encounter(docname) - - if lab_test_created: - frappe.msgprint(_('Lab Test(s) {0} created successfully').format(lab_test_created), indicator='green') - else: - frappe.msgprint(_('No Lab Tests created')) - -def create_lab_test_from_encounter(encounter): - lab_test_created = False - encounter = frappe.get_doc('Patient Encounter', encounter) - - if encounter and encounter.lab_test_prescription: - patient = frappe.get_doc('Patient', encounter.patient) - for item in encounter.lab_test_prescription: - if not item.lab_test_created: - template = get_lab_test_template(item.lab_test_code) - if template: - lab_test = create_lab_test_doc(item.invoiced, encounter.practitioner, patient, template, encounter.company) - lab_test.save(ignore_permissions = True) - frappe.db.set_value('Lab Prescription', item.name, 'lab_test_created', 1) - if not lab_test_created: - lab_test_created = lab_test.name - else: - lab_test_created += ', ' + lab_test.name - return lab_test_created - - -def create_lab_test_from_invoice(sales_invoice): - lab_tests_created = False - invoice = frappe.get_doc('Sales Invoice', sales_invoice) - if invoice and invoice.patient: - patient = frappe.get_doc('Patient', invoice.patient) - for item in invoice.items: - lab_test_created = 0 - if item.reference_dt == 'Lab Prescription': - lab_test_created = frappe.db.get_value('Lab Prescription', item.reference_dn, 'lab_test_created') - elif item.reference_dt == 'Lab Test': - lab_test_created = 1 - if lab_test_created != 1: - template = get_lab_test_template(item.item_code) - if template: - lab_test = create_lab_test_doc(True, invoice.ref_practitioner, patient, template, invoice.company) - if item.reference_dt == 'Lab Prescription': - lab_test.prescription = item.reference_dn - lab_test.save(ignore_permissions = True) - if item.reference_dt != 'Lab Prescription': - frappe.db.set_value('Sales Invoice Item', item.name, 'reference_dt', 'Lab Test') - frappe.db.set_value('Sales Invoice Item', item.name, 'reference_dn', lab_test.name) - if not lab_tests_created: - lab_tests_created = lab_test.name - else: - lab_tests_created += ', ' + lab_test.name - return lab_tests_created - -def get_lab_test_template(item): - template_id = frappe.db.exists('Lab Test Template', {'item': item}) - if template_id: - return frappe.get_doc('Lab Test Template', template_id) - return False - -def create_lab_test_doc(invoiced, practitioner, patient, template, company): - lab_test = frappe.new_doc('Lab Test') - lab_test.invoiced = invoiced - lab_test.practitioner = practitioner - lab_test.patient = patient.name - lab_test.patient_age = patient.get_age() - lab_test.patient_sex = patient.sex - lab_test.email = patient.email - lab_test.mobile = patient.mobile - lab_test.report_preference = patient.report_preference - lab_test.department = template.department - lab_test.template = template.name - lab_test.lab_test_group = template.lab_test_group - lab_test.result_date = getdate() - lab_test.company = company - return lab_test - -def create_normals(template, lab_test): - lab_test.normal_toggle = 1 - normal = lab_test.append('normal_test_items') - normal.lab_test_name = template.lab_test_name - normal.lab_test_uom = template.lab_test_uom - normal.secondary_uom = template.secondary_uom - normal.conversion_factor = template.conversion_factor - normal.normal_range = template.lab_test_normal_range - normal.require_result_value = 1 - normal.allow_blank = 0 - normal.template = template.name - -def create_compounds(template, lab_test, is_group): - lab_test.normal_toggle = 1 - for normal_test_template in template.normal_test_templates: - normal = lab_test.append('normal_test_items') - if is_group: - normal.lab_test_event = normal_test_template.lab_test_event - else: - normal.lab_test_name = normal_test_template.lab_test_event - - normal.lab_test_uom = normal_test_template.lab_test_uom - normal.secondary_uom = normal_test_template.secondary_uom - normal.conversion_factor = normal_test_template.conversion_factor - normal.normal_range = normal_test_template.normal_range - normal.require_result_value = 1 - normal.allow_blank = normal_test_template.allow_blank - normal.template = template.name - -def create_descriptives(template, lab_test): - lab_test.descriptive_toggle = 1 - if template.sensitivity: - lab_test.sensitivity_toggle = 1 - for descriptive_test_template in template.descriptive_test_templates: - descriptive = lab_test.append('descriptive_test_items') - descriptive.lab_test_particulars = descriptive_test_template.particulars - descriptive.require_result_value = 1 - descriptive.allow_blank = descriptive_test_template.allow_blank - descriptive.template = template.name - -def create_sample_doc(template, patient, invoice, company = None): - if template.sample: - sample_exists = frappe.db.exists({ - 'doctype': 'Sample Collection', - 'patient': patient.name, - 'docstatus': 0, - 'sample': template.sample - }) - - if sample_exists: - # update sample collection by adding quantity - sample_collection = frappe.get_doc('Sample Collection', sample_exists[0][0]) - quantity = int(sample_collection.sample_qty) + int(template.sample_qty) - if template.sample_details: - sample_details = sample_collection.sample_details + '\n-\n' + _('Test :') - sample_details += (template.get('lab_test_name') or template.get('template')) + '\n' - sample_details += _('Collection Details:') + '\n\t' + template.sample_details - frappe.db.set_value('Sample Collection', sample_collection.name, 'sample_details', sample_details) - - frappe.db.set_value('Sample Collection', sample_collection.name, 'sample_qty', quantity) - - else: - # Create Sample Collection for template, copy vals from Invoice - sample_collection = frappe.new_doc('Sample Collection') - if invoice: - sample_collection.invoiced = True - - sample_collection.patient = patient.name - sample_collection.patient_age = patient.get_age() - sample_collection.patient_sex = patient.sex - sample_collection.sample = template.sample - sample_collection.sample_uom = template.sample_uom - sample_collection.sample_qty = template.sample_qty - sample_collection.company = company - - if template.sample_details: - sample_collection.sample_details = _('Test :') + (template.get('lab_test_name') or template.get('template')) + '\n' + 'Collection Detials:\n\t' + template.sample_details - sample_collection.save(ignore_permissions=True) - - return sample_collection - -def create_sample_collection(lab_test, template, patient, invoice): - if frappe.get_cached_value('Healthcare Settings', None, 'create_sample_collection_for_lab_test'): - sample_collection = create_sample_doc(template, patient, invoice, lab_test.company) - if sample_collection: - lab_test.sample = sample_collection.name - sample_collection_doc = get_link_to_form('Sample Collection', sample_collection.name) - frappe.msgprint(_('Sample Collection {0} has been created').format(sample_collection_doc), - title=_('Sample Collection'), indicator='green') - return lab_test - -def load_result_format(lab_test, template, prescription, invoice): - if template.lab_test_template_type == 'Single': - create_normals(template, lab_test) - - elif template.lab_test_template_type == 'Compound': - create_compounds(template, lab_test, False) - - elif template.lab_test_template_type == 'Descriptive': - create_descriptives(template, lab_test) - - elif template.lab_test_template_type == 'Grouped': - # Iterate for each template in the group and create one result for all. - for lab_test_group in template.lab_test_groups: - # Template_in_group = None - if lab_test_group.lab_test_template: - template_in_group = frappe.get_doc('Lab Test Template', lab_test_group.lab_test_template) - if template_in_group: - if template_in_group.lab_test_template_type == 'Single': - create_normals(template_in_group, lab_test) - - elif template_in_group.lab_test_template_type == 'Compound': - normal_heading = lab_test.append('normal_test_items') - normal_heading.lab_test_name = template_in_group.lab_test_name - normal_heading.require_result_value = 0 - normal_heading.allow_blank = 1 - normal_heading.template = template_in_group.name - create_compounds(template_in_group, lab_test, True) - - elif template_in_group.lab_test_template_type == 'Descriptive': - descriptive_heading = lab_test.append('descriptive_test_items') - descriptive_heading.lab_test_name = template_in_group.lab_test_name - descriptive_heading.require_result_value = 0 - descriptive_heading.allow_blank = 1 - descriptive_heading.template = template_in_group.name - create_descriptives(template_in_group, lab_test) - - else: # Lab Test Group - Add New Line - normal = lab_test.append('normal_test_items') - normal.lab_test_name = lab_test_group.group_event - normal.lab_test_uom = lab_test_group.group_test_uom - normal.secondary_uom = lab_test_group.secondary_uom - normal.conversion_factor = lab_test_group.conversion_factor - normal.normal_range = lab_test_group.group_test_normal_range - normal.allow_blank = lab_test_group.allow_blank - normal.require_result_value = 1 - normal.template = template.name - - if template.lab_test_template_type != 'No Result': - if prescription: - lab_test.prescription = prescription - if invoice: - frappe.db.set_value('Lab Prescription', prescription, 'invoiced', True) - lab_test.save(ignore_permissions=True) # Insert the result - return lab_test - -@frappe.whitelist() -def get_employee_by_user_id(user_id): - emp_id = frappe.db.exists('Employee', { 'user_id': user_id }) - if emp_id: - return frappe.get_doc('Employee', emp_id) - return None - - -@frappe.whitelist() -def get_lab_test_prescribed(patient): - return frappe.db.sql( - ''' - select - lp.name, - lp.lab_test_code, - lp.parent, - lp.invoiced, - pe.practitioner, - pe.practitioner_name, - pe.encounter_date - from - `tabPatient Encounter` pe, `tabLab Prescription` lp - where - pe.patient=%s - and lp.parent=pe.name - and lp.lab_test_created=0 - ''', (patient)) diff --git a/erpnext/healthcare/doctype/lab_test/lab_test_list.js b/erpnext/healthcare/doctype/lab_test/lab_test_list.js deleted file mode 100644 index 7b5b9d922a9..00000000000 --- a/erpnext/healthcare/doctype/lab_test/lab_test_list.js +++ /dev/null @@ -1,71 +0,0 @@ -/* -(c) ESS 2015-16 -*/ -frappe.listview_settings['Lab Test'] = { - add_fields: ['name', 'status', 'invoiced'], - filters: [['docstatus', '=', '1']], - get_indicator: function (doc) { - if (doc.status === 'Approved') { - return [__('Approved'), 'green', 'status, =, Approved']; - } else if (doc.status === 'Rejected') { - return [__('Rejected'), 'orange', 'status, =, Rejected']; - } else if (doc.status === 'Completed') { - return [__('Completed'), 'green', 'status, =, Completed']; - } else if (doc.status === 'Cancelled') { - return [__('Cancelled'), 'red', 'status, =, Cancelled']; - } - }, - onload: function (listview) { - listview.page.add_menu_item(__('Create Multiple'), function () { - create_multiple_dialog(listview); - }); - } -}; - -var create_multiple_dialog = function (listview) { - var dialog = new frappe.ui.Dialog({ - title: 'Create Multiple Lab Tests', - width: 100, - fields: [ - { fieldtype: 'Link', label: 'Patient', fieldname: 'patient', options: 'Patient', reqd: 1 }, - { - fieldtype: 'Select', label: 'Invoice / Patient Encounter', fieldname: 'doctype', - options: '\nSales Invoice\nPatient Encounter', reqd: 1 - }, - { - fieldtype: 'Dynamic Link', fieldname: 'docname', options: 'doctype', reqd: 1, - get_query: function () { - return { - filters: { - 'patient': dialog.get_value('patient'), - 'docstatus': 1 - } - }; - } - } - ], - primary_action_label: __('Create'), - primary_action: function () { - frappe.call({ - method: 'erpnext.healthcare.doctype.lab_test.lab_test.create_multiple', - args: { - 'doctype': dialog.get_value('doctype'), - 'docname': dialog.get_value('docname') - }, - callback: function (data) { - if (!data.exc) { - if (!data.message) { - frappe.msgprint(__('No Lab Tests created')); - } - listview.refresh(); - } - }, - freeze: true, - freeze_message: __('Creating Lab Tests...') - }); - dialog.hide(); - } - }); - - dialog.show(); -}; diff --git a/erpnext/healthcare/doctype/lab_test/test_lab_test.py b/erpnext/healthcare/doctype/lab_test/test_lab_test.py deleted file mode 100644 index da10bd86bdf..00000000000 --- a/erpnext/healthcare/doctype/lab_test/test_lab_test.py +++ /dev/null @@ -1,215 +0,0 @@ -# -*- coding: utf-8 -*- -# Copyright (c) 2015, ESS LLP and Contributors -# See license.txt -from __future__ import unicode_literals - -import unittest - -import frappe -from frappe.utils import getdate, nowtime - -from erpnext.healthcare.doctype.healthcare_settings.healthcare_settings import ( - get_income_account, - get_receivable_account, -) -from erpnext.healthcare.doctype.lab_test.lab_test import create_multiple -from erpnext.healthcare.doctype.patient_appointment.test_patient_appointment import create_patient -from erpnext.healthcare.doctype.patient_medical_record.test_patient_medical_record import ( - create_lab_test_template as create_blood_test_template, -) - - -class TestLabTest(unittest.TestCase): - def test_lab_test_item(self): - lab_template = create_lab_test_template() - self.assertTrue(frappe.db.exists('Item', lab_template.item)) - self.assertEqual(frappe.db.get_value('Item Price', {'item_code':lab_template.item}, 'price_list_rate'), lab_template.lab_test_rate) - - lab_template.disabled = 1 - lab_template.save() - self.assertEqual(frappe.db.get_value('Item', lab_template.item, 'disabled'), 1) - - lab_template.reload() - - lab_template.disabled = 0 - lab_template.save() - - def test_descriptive_lab_test(self): - lab_template = create_lab_test_template() - - # blank result value not allowed as per template - lab_test = create_lab_test(lab_template) - lab_test.descriptive_test_items[0].result_value = 12 - lab_test.descriptive_test_items[2].result_value = 1 - lab_test.save() - self.assertRaises(frappe.ValidationError, lab_test.submit) - - def test_sample_collection(self): - frappe.db.set_value('Healthcare Settings', 'Healthcare Settings', 'create_sample_collection_for_lab_test', 1) - lab_template = create_lab_test_template() - - lab_test = create_lab_test(lab_template) - lab_test.descriptive_test_items[0].result_value = 12 - lab_test.descriptive_test_items[1].result_value = 1 - lab_test.descriptive_test_items[2].result_value = 2.3 - lab_test.save() - - # check sample collection created - self.assertTrue(frappe.db.exists('Sample Collection', {'sample': lab_template.sample})) - - frappe.db.set_value('Healthcare Settings', 'Healthcare Settings', 'create_sample_collection_for_lab_test', 0) - lab_test = create_lab_test(lab_template) - lab_test.descriptive_test_items[0].result_value = 12 - lab_test.descriptive_test_items[1].result_value = 1 - lab_test.descriptive_test_items[2].result_value = 2.3 - lab_test.save() - - # sample collection should not be created - lab_test.reload() - self.assertEqual(lab_test.sample, None) - - def test_create_lab_tests_from_sales_invoice(self): - sales_invoice = create_sales_invoice() - create_multiple('Sales Invoice', sales_invoice.name) - sales_invoice.reload() - self.assertIsNotNone(sales_invoice.items[0].reference_dn) - self.assertIsNotNone(sales_invoice.items[1].reference_dn) - - def test_create_lab_tests_from_patient_encounter(self): - patient_encounter = create_patient_encounter() - create_multiple('Patient Encounter', patient_encounter.name) - patient_encounter.reload() - self.assertTrue(patient_encounter.lab_test_prescription[0].lab_test_created) - self.assertTrue(patient_encounter.lab_test_prescription[0].lab_test_created) - - -def create_lab_test_template(test_sensitivity=0, sample_collection=1): - medical_department = create_medical_department() - if frappe.db.exists('Lab Test Template', 'Insulin Resistance'): - return frappe.get_doc('Lab Test Template', 'Insulin Resistance') - template = frappe.new_doc('Lab Test Template') - template.lab_test_name = 'Insulin Resistance' - template.lab_test_template_type = 'Descriptive' - template.lab_test_code = 'Insulin Resistance' - template.lab_test_group = 'Services' - template.department = medical_department - template.is_billable = 1 - template.lab_test_description = 'Insulin Resistance' - template.lab_test_rate = 2000 - - for entry in ['FBS', 'Insulin', 'IR']: - template.append('descriptive_test_templates', { - 'particulars': entry, - 'allow_blank': 1 if entry=='IR' else 0 - }) - - if test_sensitivity: - template.sensitivity = 1 - - if sample_collection: - template.sample = create_lab_test_sample() - template.sample_qty = 5.0 - - template.save() - return template - -def create_medical_department(): - medical_department = frappe.db.exists('Medical Department', '_Test Medical Department') - if not medical_department: - medical_department = frappe.new_doc('Medical Department') - medical_department.department = '_Test Medical Department' - medical_department.save() - medical_department = medical_department.name - - return medical_department - -def create_lab_test(lab_template): - patient = create_patient() - lab_test = frappe.new_doc('Lab Test') - lab_test.template = lab_template.name - lab_test.patient = patient - lab_test.patient_sex = 'Female' - lab_test.save() - - return lab_test - -def create_lab_test_sample(): - blood_sample = frappe.db.exists('Lab Test Sample', 'Blood Sample') - if blood_sample: - return blood_sample - - sample = frappe.new_doc('Lab Test Sample') - sample.sample = 'Blood Sample' - sample.sample_uom = 'U/ml' - sample.save() - - return sample.name - -def create_sales_invoice(): - patient = create_patient() - medical_department = create_medical_department() - insulin_resistance_template = create_lab_test_template() - blood_test_template = create_blood_test_template(medical_department) - - sales_invoice = frappe.new_doc('Sales Invoice') - sales_invoice.patient = patient - sales_invoice.customer = frappe.db.get_value('Patient', patient, 'customer') - sales_invoice.due_date = getdate() - sales_invoice.company = '_Test Company' - sales_invoice.debit_to = get_receivable_account('_Test Company') - - tests = [insulin_resistance_template, blood_test_template] - for entry in tests: - sales_invoice.append('items', { - 'item_code': entry.item, - 'item_name': entry.lab_test_name, - 'description': entry.lab_test_description, - 'qty': 1, - 'uom': 'Nos', - 'conversion_factor': 1, - 'income_account': get_income_account(None, '_Test Company'), - 'rate': entry.lab_test_rate, - 'amount': entry.lab_test_rate - }) - - sales_invoice.set_missing_values() - - sales_invoice.submit() - return sales_invoice - -def create_patient_encounter(): - patient = create_patient() - medical_department = create_medical_department() - insulin_resistance_template = create_lab_test_template() - blood_test_template = create_blood_test_template(medical_department) - - patient_encounter = frappe.new_doc('Patient Encounter') - patient_encounter.patient = patient - patient_encounter.practitioner = create_practitioner() - patient_encounter.encounter_date = getdate() - patient_encounter.encounter_time = nowtime() - - tests = [insulin_resistance_template, blood_test_template] - for entry in tests: - patient_encounter.append('lab_test_prescription', { - 'lab_test_code': entry.item, - 'lab_test_name': entry.lab_test_name - }) - - patient_encounter.submit() - return patient_encounter - - -def create_practitioner(): - practitioner = frappe.db.exists('Healthcare Practitioner', '_Test Healthcare Practitioner') - - if not practitioner: - practitioner = frappe.new_doc('Healthcare Practitioner') - practitioner.first_name = '_Test Healthcare Practitioner' - practitioner.gender = 'Female' - practitioner.op_consulting_charge = 500 - practitioner.inpatient_visit_charge = 500 - practitioner.save(ignore_permissions=True) - practitioner = practitioner.name - - return practitioner diff --git a/erpnext/healthcare/doctype/lab_test_group_template/__init__.py b/erpnext/healthcare/doctype/lab_test_group_template/__init__.py deleted file mode 100644 index e69de29bb2d..00000000000 diff --git a/erpnext/healthcare/doctype/lab_test_group_template/lab_test_group_template.json b/erpnext/healthcare/doctype/lab_test_group_template/lab_test_group_template.json deleted file mode 100644 index 2767f7ec778..00000000000 --- a/erpnext/healthcare/doctype/lab_test_group_template/lab_test_group_template.json +++ /dev/null @@ -1,119 +0,0 @@ -{ - "actions": [], - "allow_copy": 1, - "beta": 1, - "creation": "2016-03-29 17:37:29.913583", - "doctype": "DocType", - "document_type": "Setup", - "engine": "InnoDB", - "field_order": [ - "template_or_new_line", - "lab_test_template", - "lab_test_rate", - "lab_test_description", - "group_event", - "group_test_uom", - "secondary_uom", - "conversion_factor", - "allow_blank", - "column_break_8", - "group_test_normal_range" - ], - "fields": [ - { - "default": "Add Test", - "fieldname": "template_or_new_line", - "fieldtype": "Select", - "options": "Add Test\nAdd New Line", - "print_hide": 1, - "report_hide": 1 - }, - { - "depends_on": "eval:doc.template_or_new_line == 'Add Test'", - "fieldname": "lab_test_template", - "fieldtype": "Link", - "ignore_user_permissions": 1, - "in_list_view": 1, - "label": "Test Name", - "options": "Lab Test Template" - }, - { - "fetch_from": "lab_test_template.lab_test_rate", - "fieldname": "lab_test_rate", - "fieldtype": "Currency", - "label": "Rate", - "print_hide": 1, - "read_only": 1, - "report_hide": 1 - }, - { - "fetch_from": "lab_test_template.lab_test_description", - "fieldname": "lab_test_description", - "fieldtype": "Data", - "ignore_xss_filter": 1, - "in_list_view": 1, - "label": "Description", - "read_only": 1 - }, - { - "depends_on": "eval:doc.template_or_new_line == 'Add New Line'", - "fieldname": "group_event", - "fieldtype": "Data", - "ignore_xss_filter": 1, - "in_list_view": 1, - "label": "Event" - }, - { - "depends_on": "eval:doc.template_or_new_line =='Add New Line'", - "fieldname": "group_test_uom", - "fieldtype": "Link", - "ignore_user_permissions": 1, - "label": "UOM", - "options": "Lab Test UOM" - }, - { - "depends_on": "eval:doc.template_or_new_line == 'Add New Line'", - "fieldname": "group_test_normal_range", - "fieldtype": "Long Text", - "ignore_xss_filter": 1, - "label": "Normal Range" - }, - { - "fieldname": "column_break_8", - "fieldtype": "Column Break" - }, - { - "depends_on": "eval:doc.template_or_new_line =='Add New Line'", - "fieldname": "secondary_uom", - "fieldtype": "Link", - "label": "Secondary UOM", - "options": "Lab Test UOM" - }, - { - "depends_on": "secondary_uom", - "fieldname": "conversion_factor", - "fieldtype": "Float", - "label": "Conversion Factor", - "mandatory_depends_on": "secondary_uom" - }, - { - "default": "0", - "depends_on": "eval:doc.template_or_new_line == 'Add New Line'", - "fieldname": "allow_blank", - "fieldtype": "Check", - "in_list_view": 1, - "label": "Allow Blank" - } - ], - "istable": 1, - "links": [], - "modified": "2020-07-30 12:36:03.082391", - "modified_by": "Administrator", - "module": "Healthcare", - "name": "Lab Test Group Template", - "owner": "Administrator", - "permissions": [], - "restrict_to_domain": "Healthcare", - "sort_field": "modified", - "sort_order": "DESC" -} \ No newline at end of file diff --git a/erpnext/healthcare/doctype/lab_test_group_template/lab_test_group_template.py b/erpnext/healthcare/doctype/lab_test_group_template/lab_test_group_template.py deleted file mode 100644 index 2e3c4093c7c..00000000000 --- a/erpnext/healthcare/doctype/lab_test_group_template/lab_test_group_template.py +++ /dev/null @@ -1,11 +0,0 @@ -# -*- coding: utf-8 -*- -# Copyright (c) 2015, ESS and contributors -# For license information, please see license.txt - -from __future__ import unicode_literals - -from frappe.model.document import Document - - -class LabTestGroupTemplate(Document): - pass diff --git a/erpnext/healthcare/doctype/lab_test_sample/__init__.py b/erpnext/healthcare/doctype/lab_test_sample/__init__.py deleted file mode 100644 index e69de29bb2d..00000000000 diff --git a/erpnext/healthcare/doctype/lab_test_sample/lab_test_sample.js b/erpnext/healthcare/doctype/lab_test_sample/lab_test_sample.js deleted file mode 100644 index a5f4b4de996..00000000000 --- a/erpnext/healthcare/doctype/lab_test_sample/lab_test_sample.js +++ /dev/null @@ -1,5 +0,0 @@ -// Copyright (c) 2017, Frappe Technologies Pvt. Ltd. and contributors -// For license information, please see license.txt - -frappe.ui.form.on('Lab Test Sample', { -}); diff --git a/erpnext/healthcare/doctype/lab_test_sample/lab_test_sample.py b/erpnext/healthcare/doctype/lab_test_sample/lab_test_sample.py deleted file mode 100644 index 3a765fe2436..00000000000 --- a/erpnext/healthcare/doctype/lab_test_sample/lab_test_sample.py +++ /dev/null @@ -1,11 +0,0 @@ -# -*- coding: utf-8 -*- -# Copyright (c) 2017, Frappe Technologies Pvt. Ltd. and contributors -# For license information, please see license.txt - -from __future__ import unicode_literals - -from frappe.model.document import Document - - -class LabTestSample(Document): - pass diff --git a/erpnext/healthcare/doctype/lab_test_sample/test_lab_test_sample.py b/erpnext/healthcare/doctype/lab_test_sample/test_lab_test_sample.py deleted file mode 100644 index 8896572d783..00000000000 --- a/erpnext/healthcare/doctype/lab_test_sample/test_lab_test_sample.py +++ /dev/null @@ -1,10 +0,0 @@ -# -*- coding: utf-8 -*- -# Copyright (c) 2017, Frappe Technologies Pvt. Ltd. and Contributors -# See license.txt -from __future__ import unicode_literals - -import unittest - - -class TestLabTestSample(unittest.TestCase): - pass diff --git a/erpnext/healthcare/doctype/lab_test_template/__init__.py b/erpnext/healthcare/doctype/lab_test_template/__init__.py deleted file mode 100644 index e69de29bb2d..00000000000 diff --git a/erpnext/healthcare/doctype/lab_test_template/lab_test_template.js b/erpnext/healthcare/doctype/lab_test_template/lab_test_template.js deleted file mode 100644 index 2e41f518f04..00000000000 --- a/erpnext/healthcare/doctype/lab_test_template/lab_test_template.js +++ /dev/null @@ -1,97 +0,0 @@ -// Copyright (c) 2016, ESS -// License: ESS license.txt - -frappe.ui.form.on('Lab Test Template', { - lab_test_name: function(frm) { - if (!frm.doc.lab_test_code) - frm.set_value('lab_test_code', frm.doc.lab_test_name); - if (!frm.doc.lab_test_description) - frm.set_value('lab_test_description', frm.doc.lab_test_name); - }, - refresh : function(frm) { - // Restrict Special, Grouped type templates in Child Test Groups - frm.set_query('lab_test_template', 'lab_test_groups', function() { - return { - filters: { - lab_test_template_type: ['in', ['Single','Compound']] - } - }; - }); - }, - medical_code: function(frm) { - frm.set_query('medical_code', function() { - return { - filters: { - medical_code_standard: frm.doc.medical_code_standard - } - }; - }); - } -}); - -cur_frm.cscript.custom_refresh = function(doc) { - cur_frm.set_df_property('lab_test_code', 'read_only', doc.__islocal ? 0 : 1); - - if (!doc.__islocal) { - cur_frm.add_custom_button(__('Change Template Code'), function() { - change_template_code(doc); - }); - } -}; - -let change_template_code = function(doc) { - let d = new frappe.ui.Dialog({ - title:__('Change Template Code'), - fields:[ - { - 'fieldtype': 'Data', - 'label': 'Lab Test Template Code', - 'fieldname': 'lab_test_code', - reqd: 1 - } - ], - primary_action: function() { - let values = d.get_values(); - if (values) { - frappe.call({ - 'method': 'erpnext.healthcare.doctype.lab_test_template.lab_test_template.change_test_code_from_template', - 'args': {lab_test_code: values.lab_test_code, doc: doc}, - callback: function (data) { - frappe.set_route('Form', 'Lab Test Template', data.message); - } - }); - } - d.hide(); - }, - primary_action_label: __('Change Template Code') - }); - d.show(); - - d.set_values({ - 'lab_test_code': doc.lab_test_code - }); -}; - -frappe.ui.form.on('Lab Test Template', 'lab_test_name', function(frm) { - frm.doc.change_in_item = 1; -}); - -frappe.ui.form.on('Lab Test Template', 'lab_test_rate', function(frm) { - frm.doc.change_in_item = 1; -}); - -frappe.ui.form.on('Lab Test Template', 'lab_test_group', function(frm) { - frm.doc.change_in_item = 1; -}); - -frappe.ui.form.on('Lab Test Template', 'lab_test_description', function(frm) { - frm.doc.change_in_item = 1; -}); - -frappe.ui.form.on('Lab Test Groups', 'template_or_new_line', function (frm, cdt, cdn) { - let child = locals[cdt][cdn]; - if (child.template_or_new_line == 'Add New Line') { - frappe.model.set_value(cdt, cdn, 'lab_test_template', ''); - frappe.model.set_value(cdt, cdn, 'lab_test_description', ''); - } -}); diff --git a/erpnext/healthcare/doctype/lab_test_template/lab_test_template.json b/erpnext/healthcare/doctype/lab_test_template/lab_test_template.json deleted file mode 100644 index c3fc8420477..00000000000 --- a/erpnext/healthcare/doctype/lab_test_template/lab_test_template.json +++ /dev/null @@ -1,356 +0,0 @@ -{ - "actions": [], - "allow_copy": 1, - "allow_import": 1, - "allow_rename": 1, - "autoname": "field:lab_test_code", - "beta": 1, - "creation": "2016-03-29 17:35:36.761223", - "doctype": "DocType", - "engine": "InnoDB", - "field_order": [ - "lab_test_name", - "item", - "lab_test_code", - "lab_test_group", - "department", - "column_break_3", - "disabled", - "lab_test_template_type", - "is_billable", - "lab_test_rate", - "section_break_description", - "lab_test_description", - "section_break_normal", - "lab_test_uom", - "secondary_uom", - "conversion_factor", - "column_break_10", - "lab_test_normal_range", - "section_break_compound", - "normal_test_templates", - "section_break_special", - "sensitivity", - "descriptive_test_templates", - "section_break_group", - "lab_test_groups", - "sb_sample_collection", - "sample", - "sample_uom", - "sample_qty", - "column_break_33", - "sample_details", - "medical_coding_section", - "medical_code", - "medical_code_standard", - "worksheet_section", - "worksheet_instructions", - "result_legend_section", - "legend_print_position", - "result_legend", - "change_in_item" - ], - "fields": [ - { - "fieldname": "lab_test_name", - "fieldtype": "Data", - "in_list_view": 1, - "in_standard_filter": 1, - "label": "Test Name", - "no_copy": 1, - "reqd": 1, - "search_index": 1 - }, - { - "fieldname": "item", - "fieldtype": "Link", - "label": "Item", - "no_copy": 1, - "options": "Item", - "read_only": 1, - "search_index": 1 - }, - { - "fieldname": "lab_test_code", - "fieldtype": "Data", - "in_list_view": 1, - "label": "Item Code", - "no_copy": 1, - "reqd": 1, - "unique": 1 - }, - { - "fieldname": "lab_test_group", - "fieldtype": "Link", - "ignore_user_permissions": 1, - "in_standard_filter": 1, - "label": "Item Group", - "options": "Item Group", - "reqd": 1, - "search_index": 1 - }, - { - "fieldname": "department", - "fieldtype": "Link", - "ignore_user_permissions": 1, - "in_standard_filter": 1, - "label": "Department", - "options": "Medical Department", - "reqd": 1 - }, - { - "fieldname": "column_break_3", - "fieldtype": "Column Break" - }, - { - "description": "Single: Results which require only a single input.\n
\nCompound: Results which require multiple event inputs.\n
\nDescriptive: Tests which have multiple result components with manual result entry.\n
\nGrouped: Test templates which are a group of other test templates.\n
\nNo Result: Tests with no results, can be ordered and billed but no Lab Test will be created. e.g.. Sub Tests for Grouped results", - "fieldname": "lab_test_template_type", - "fieldtype": "Select", - "in_standard_filter": 1, - "label": "Result Format", - "options": "\nSingle\nCompound\nDescriptive\nGrouped\nNo Result" - }, - { - "default": "1", - "depends_on": "eval:doc.lab_test_template_type != 'Grouped'", - "description": "If unchecked, the item will not be available in Sales Invoices for billing but can be used in group test creation. ", - "fieldname": "is_billable", - "fieldtype": "Check", - "label": "Is Billable", - "search_index": 1 - }, - { - "depends_on": "eval:doc.is_billable == 1", - "description": "This value is updated in the Default Sales Price List.", - "fieldname": "lab_test_rate", - "fieldtype": "Currency", - "in_list_view": 1, - "label": "Rate", - "mandatory_depends_on": "eval:doc.is_billable == 1" - }, - { - "collapsible": 1, - "fieldname": "medical_coding_section", - "fieldtype": "Section Break", - "label": "Medical Coding" - }, - { - "depends_on": "medical_code_standard", - "fieldname": "medical_code", - "fieldtype": "Link", - "label": "Medical Code", - "options": "Medical Code" - }, - { - "fieldname": "medical_code_standard", - "fieldtype": "Link", - "label": "Medical Code Standard", - "options": "Medical Code Standard" - }, - { - "depends_on": "eval:doc.lab_test_template_type == 'Single'", - "fieldname": "section_break_normal", - "fieldtype": "Section Break", - "label": "Lab Routine" - }, - { - "fieldname": "lab_test_uom", - "fieldtype": "Link", - "ignore_user_permissions": 1, - "in_list_view": 1, - "label": "UOM", - "options": "Lab Test UOM" - }, - { - "fieldname": "lab_test_normal_range", - "fieldtype": "Long Text", - "ignore_xss_filter": 1, - "label": "Normal Range" - }, - { - "fieldname": "column_break_10", - "fieldtype": "Column Break" - }, - { - "depends_on": "eval:doc.lab_test_template_type == 'Compound'", - "fieldname": "section_break_compound", - "fieldtype": "Section Break", - "label": "Compound" - }, - { - "fieldname": "normal_test_templates", - "fieldtype": "Table", - "options": "Normal Test Template" - }, - { - "depends_on": "eval:doc.lab_test_template_type == 'Descriptive'", - "fieldname": "section_break_special", - "fieldtype": "Section Break", - "label": "Descriptive Test" - }, - { - "default": "0", - "fieldname": "sensitivity", - "fieldtype": "Check", - "label": "Sensitivity" - }, - { - "depends_on": "eval:doc.lab_test_template_type == 'Grouped'", - "fieldname": "section_break_group", - "fieldtype": "Section Break", - "label": "Group Tests" - }, - { - "fieldname": "lab_test_groups", - "fieldtype": "Table", - "options": "Lab Test Group Template" - }, - { - "collapsible": 1, - "fieldname": "section_break_description", - "fieldtype": "Section Break", - "label": "Description " - }, - { - "fieldname": "lab_test_description", - "fieldtype": "Text Editor", - "ignore_xss_filter": 1, - "label": "Description", - "no_copy": 1 - }, - { - "fieldname": "sb_sample_collection", - "fieldtype": "Section Break", - "label": "Sample Collection" - }, - { - "fieldname": "sample", - "fieldtype": "Link", - "ignore_user_permissions": 1, - "label": "Sample", - "options": "Lab Test Sample" - }, - { - "fetch_from": "sample.sample_uom", - "fieldname": "sample_uom", - "fieldtype": "Data", - "label": "UOM", - "read_only": 1 - }, - { - "default": "0", - "fieldname": "change_in_item", - "fieldtype": "Check", - "hidden": 1, - "label": "Change In Item", - "no_copy": 1, - "print_hide": 1, - "report_hide": 1 - }, - { - "default": "0", - "fieldname": "disabled", - "fieldtype": "Check", - "label": "Disabled" - }, - { - "default": "0", - "fieldname": "sample_qty", - "fieldtype": "Float", - "label": "Quantity" - }, - { - "fieldname": "sample_details", - "fieldtype": "Small Text", - "ignore_xss_filter": 1, - "label": "Collection Details" - }, - { - "collapsible": 1, - "description": "Information to help easily interpret the test report, will be printed as part of the Lab Test result.", - "fieldname": "result_legend_section", - "fieldtype": "Section Break", - "label": "Result Legend Print" - }, - { - "fieldname": "result_legend", - "fieldtype": "Text Editor", - "label": "Result Legend" - }, - { - "fieldname": "legend_print_position", - "fieldtype": "Select", - "label": "Print Position", - "options": "Bottom\nTop\nBoth" - }, - { - "fieldname": "secondary_uom", - "fieldtype": "Link", - "label": "Secondary UOM", - "options": "Lab Test UOM" - }, - { - "depends_on": "secondary_uom", - "fieldname": "conversion_factor", - "fieldtype": "Float", - "label": "Conversion Factor", - "mandatory_depends_on": "secondary_uom" - }, - { - "description": "Instructions to be printed on the worksheet", - "fieldname": "worksheet_instructions", - "fieldtype": "Text Editor", - "label": "Worksheet Instructions" - }, - { - "collapsible": 1, - "fieldname": "worksheet_section", - "fieldtype": "Section Break", - "label": "Worksheet Print" - }, - { - "fieldname": "descriptive_test_templates", - "fieldtype": "Table", - "options": "Descriptive Test Template" - }, - { - "fieldname": "column_break_33", - "fieldtype": "Column Break" - } - ], - "links": [], - "modified": "2020-07-30 14:32:40.449818", - "modified_by": "Administrator", - "module": "Healthcare", - "name": "Lab Test Template", - "owner": "Administrator", - "permissions": [ - { - "create": 1, - "delete": 1, - "email": 1, - "export": 1, - "print": 1, - "read": 1, - "report": 1, - "role": "Healthcare Administrator", - "share": 1, - "write": 1 - }, - { - "email": 1, - "export": 1, - "print": 1, - "read": 1, - "report": 1, - "role": "Laboratory User", - "share": 1 - } - ], - "restrict_to_domain": "Healthcare", - "search_fields": "lab_test_code,lab_test_name,lab_test_template_type", - "sort_field": "modified", - "sort_order": "DESC", - "title_field": "lab_test_name", - "track_changes": 1 -} \ No newline at end of file diff --git a/erpnext/healthcare/doctype/lab_test_template/lab_test_template.py b/erpnext/healthcare/doctype/lab_test_template/lab_test_template.py deleted file mode 100644 index c052693d044..00000000000 --- a/erpnext/healthcare/doctype/lab_test_template/lab_test_template.py +++ /dev/null @@ -1,146 +0,0 @@ -# -*- coding: utf-8 -*- -# Copyright (c) 2015, ESS and contributors -# For license information, please see license.txt - -from __future__ import unicode_literals - -import json - -import frappe -from frappe import _ -from frappe.model.document import Document -from frappe.model.rename_doc import rename_doc - - -class LabTestTemplate(Document): - def after_insert(self): - if not self.item: - create_item_from_template(self) - - def validate(self): - if self.is_billable and (not self.lab_test_rate or self.lab_test_rate <= 0.0): - frappe.throw(_('Standard Selling Rate should be greater than zero.')) - - self.validate_conversion_factor() - self.enable_disable_item() - - def on_update(self): - # If change_in_item update Item and Price List - if self.change_in_item and self.is_billable and self.item: - self.update_item() - item_price = self.item_price_exists() - if not item_price: - if self.lab_test_rate and self.lab_test_rate > 0.0: - price_list_name = frappe.db.get_value('Price List', {'selling': 1}) - make_item_price(self.lab_test_code, price_list_name, self.lab_test_rate) - else: - frappe.db.set_value('Item Price', item_price, 'price_list_rate', self.lab_test_rate) - - self.db_set('change_in_item', 0) - - elif not self.is_billable and self.item: - frappe.db.set_value('Item', self.item, 'disabled', 1) - - self.reload() - - def on_trash(self): - # Remove template reference from item and disable item - if self.item: - try: - item = self.item - self.db_set('item', '') - frappe.delete_doc('Item', item) - except Exception: - frappe.throw(_('Not permitted. Please disable the Lab Test Template')) - - def enable_disable_item(self): - if self.is_billable: - if self.disabled: - frappe.db.set_value('Item', self.item, 'disabled', 1) - else: - frappe.db.set_value('Item', self.item, 'disabled', 0) - - def update_item(self): - item = frappe.get_doc('Item', self.item) - if item: - item.update({ - 'item_name': self.lab_test_name, - 'item_group': self.lab_test_group, - 'disabled': 0, - 'standard_rate': self.lab_test_rate, - 'description': self.lab_test_description - }) - item.flags.ignore_mandatory = True - item.save(ignore_permissions=True) - - def item_price_exists(self): - item_price = frappe.db.exists({'doctype': 'Item Price', 'item_code': self.lab_test_code}) - if item_price: - return item_price[0][0] - return False - - def validate_conversion_factor(self): - if self.lab_test_template_type == 'Single' and self.secondary_uom and not self.conversion_factor: - frappe.throw(_('Conversion Factor is mandatory')) - if self.lab_test_template_type == 'Compound': - for item in self.normal_test_templates: - if item.secondary_uom and not item.conversion_factor: - frappe.throw(_('Row #{0}: Conversion Factor is mandatory').format(item.idx)) - if self.lab_test_template_type == 'Grouped': - for group in self.lab_test_groups: - if group.template_or_new_line == 'Add New Line' and group.secondary_uom and not group.conversion_factor: - frappe.throw(_('Row #{0}: Conversion Factor is mandatory').format(group.idx)) - - -def create_item_from_template(doc): - uom = frappe.db.exists('UOM', 'Unit') or frappe.db.get_single_value('Stock Settings', 'stock_uom') - # Insert item - item = frappe.get_doc({ - 'doctype': 'Item', - 'item_code': doc.lab_test_code, - 'item_name':doc.lab_test_name, - 'item_group': doc.lab_test_group, - 'description':doc.lab_test_description, - 'is_sales_item': 1, - 'is_service_item': 1, - 'is_purchase_item': 0, - 'is_stock_item': 0, - 'include_item_in_manufacturing': 0, - 'show_in_website': 0, - 'is_pro_applicable': 0, - 'disabled': 0 if doc.is_billable and not doc.disabled else doc.disabled, - 'stock_uom': uom - }).insert(ignore_permissions=True, ignore_mandatory=True) - - # Insert item price - if doc.is_billable and doc.lab_test_rate != 0.0: - price_list_name = frappe.db.get_value('Price List', {'selling': 1}) - if doc.lab_test_rate: - make_item_price(item.name, price_list_name, doc.lab_test_rate) - else: - make_item_price(item.name, price_list_name, 0.0) - # Set item in the template - frappe.db.set_value('Lab Test Template', doc.name, 'item', item.name) - - doc.reload() - -def make_item_price(item, price_list_name, item_price): - frappe.get_doc({ - 'doctype': 'Item Price', - 'price_list': price_list_name, - 'item_code': item, - 'price_list_rate': item_price - }).insert(ignore_permissions=True, ignore_mandatory=True) - -@frappe.whitelist() -def change_test_code_from_template(lab_test_code, doc): - doc = frappe._dict(json.loads(doc)) - - if frappe.db.exists({'doctype': 'Item', 'item_code': lab_test_code}): - frappe.throw(_('Lab Test Item {0} already exist').format(lab_test_code)) - else: - rename_doc('Item', doc.name, lab_test_code, ignore_permissions=True) - frappe.db.set_value('Lab Test Template', doc.name, 'lab_test_code', lab_test_code) - frappe.db.set_value('Lab Test Template', doc.name, 'lab_test_name', lab_test_code) - rename_doc('Lab Test Template', doc.name, lab_test_code, ignore_permissions=True) - return lab_test_code diff --git a/erpnext/healthcare/doctype/lab_test_template/lab_test_template_dashboard.py b/erpnext/healthcare/doctype/lab_test_template/lab_test_template_dashboard.py deleted file mode 100644 index a4f9d4b714e..00000000000 --- a/erpnext/healthcare/doctype/lab_test_template/lab_test_template_dashboard.py +++ /dev/null @@ -1,15 +0,0 @@ -from __future__ import unicode_literals - -from frappe import _ - - -def get_data(): - return { - 'fieldname': 'template', - 'transactions': [ - { - 'label': _('Lab Tests'), - 'items': ['Lab Test'] - } - ] - } diff --git a/erpnext/healthcare/doctype/lab_test_template/lab_test_template_list.js b/erpnext/healthcare/doctype/lab_test_template/lab_test_template_list.js deleted file mode 100644 index 08fc2cddda2..00000000000 --- a/erpnext/healthcare/doctype/lab_test_template/lab_test_template_list.js +++ /dev/null @@ -1,7 +0,0 @@ -/* -(c) ESS 2015-16 -*/ -frappe.listview_settings['Lab Test Template'] = { - add_fields: ['lab_test_name', 'lab_test_code', 'lab_test_rate'], - filters: [['disabled', '=', 'No']] -}; diff --git a/erpnext/healthcare/doctype/lab_test_template/test_lab_test_template.py b/erpnext/healthcare/doctype/lab_test_template/test_lab_test_template.py deleted file mode 100644 index 8d8ac647500..00000000000 --- a/erpnext/healthcare/doctype/lab_test_template/test_lab_test_template.py +++ /dev/null @@ -1,11 +0,0 @@ -# -*- coding: utf-8 -*- -# Copyright (c) 2015, ESS and Contributors -# See license.txt -from __future__ import unicode_literals - -import unittest - -# test_records = frappe.get_test_records('Lab Test Template') - -class TestLabTestTemplate(unittest.TestCase): - pass diff --git a/erpnext/healthcare/doctype/lab_test_uom/__init__.py b/erpnext/healthcare/doctype/lab_test_uom/__init__.py deleted file mode 100644 index e69de29bb2d..00000000000 diff --git a/erpnext/healthcare/doctype/lab_test_uom/lab_test_uom.js b/erpnext/healthcare/doctype/lab_test_uom/lab_test_uom.js deleted file mode 100644 index 2107e79c0f6..00000000000 --- a/erpnext/healthcare/doctype/lab_test_uom/lab_test_uom.js +++ /dev/null @@ -1,5 +0,0 @@ -// Copyright (c) 2016, ESS and contributors -// For license information, please see license.txt - -frappe.ui.form.on('Lab Test UOM', { -}); diff --git a/erpnext/healthcare/doctype/lab_test_uom/lab_test_uom.json b/erpnext/healthcare/doctype/lab_test_uom/lab_test_uom.json deleted file mode 100644 index a6d52249875..00000000000 --- a/erpnext/healthcare/doctype/lab_test_uom/lab_test_uom.json +++ /dev/null @@ -1,148 +0,0 @@ -{ - "allow_copy": 1, - "allow_guest_to_view": 0, - "allow_import": 1, - "allow_rename": 1, - "autoname": "field:lab_test_uom", - "beta": 1, - "creation": "2016-03-29 17:28:08.630148", - "custom": 0, - "docstatus": 0, - "doctype": "DocType", - "document_type": "Setup", - "editable_grid": 0, - "fields": [ - { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "lab_test_uom", - "fieldtype": "Data", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 1, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 1, - "in_standard_filter": 0, - "label": "Lab Test UOM", - "length": 0, - "no_copy": 0, - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 1, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 1 - }, - { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "uom_description", - "fieldtype": "Data", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 1, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 1, - "in_standard_filter": 0, - "label": "Description", - "length": 0, - "no_copy": 0, - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 - } - ], - "has_web_view": 0, - "hide_heading": 0, - "hide_toolbar": 0, - "idx": 0, - "image_view": 0, - "in_create": 0, - "is_submittable": 0, - "issingle": 0, - "istable": 0, - "max_attachments": 0, - "modified": "2018-09-04 11:02:53.202718", - "modified_by": "Administrator", - "module": "Healthcare", - "name": "Lab Test UOM", - "name_case": "", - "owner": "Administrator", - "permissions": [ - { - "amend": 0, - "cancel": 0, - "create": 1, - "delete": 1, - "email": 1, - "export": 1, - "if_owner": 0, - "import": 0, - "permlevel": 0, - "print": 1, - "read": 1, - "report": 1, - "role": "Healthcare Administrator", - "set_user_permissions": 0, - "share": 1, - "submit": 0, - "write": 1 - }, - { - "amend": 0, - "cancel": 0, - "create": 0, - "delete": 0, - "email": 1, - "export": 1, - "if_owner": 0, - "import": 0, - "permlevel": 0, - "print": 1, - "read": 1, - "report": 1, - "role": "Laboratory User", - "set_user_permissions": 0, - "share": 1, - "submit": 0, - "write": 0 - } - ], - "quick_entry": 1, - "read_only": 0, - "read_only_onload": 0, - "restrict_to_domain": "Healthcare", - "search_fields": "lab_test_uom", - "show_name_in_global_search": 0, - "sort_field": "modified", - "sort_order": "DESC", - "title_field": "lab_test_uom", - "track_changes": 1, - "track_seen": 0, - "track_views": 0 -} \ No newline at end of file diff --git a/erpnext/healthcare/doctype/lab_test_uom/lab_test_uom.py b/erpnext/healthcare/doctype/lab_test_uom/lab_test_uom.py deleted file mode 100644 index ce11c0ffce3..00000000000 --- a/erpnext/healthcare/doctype/lab_test_uom/lab_test_uom.py +++ /dev/null @@ -1,11 +0,0 @@ -# -*- coding: utf-8 -*- -# Copyright (c) 2015, ESS and contributors -# For license information, please see license.txt - -from __future__ import unicode_literals - -from frappe.model.document import Document - - -class LabTestUOM(Document): - pass diff --git a/erpnext/healthcare/doctype/lab_test_uom/test_lab_test_uom.py b/erpnext/healthcare/doctype/lab_test_uom/test_lab_test_uom.py deleted file mode 100644 index 9fe2de51a6d..00000000000 --- a/erpnext/healthcare/doctype/lab_test_uom/test_lab_test_uom.py +++ /dev/null @@ -1,11 +0,0 @@ -# -*- coding: utf-8 -*- -# Copyright (c) 2015, ESS and Contributors -# See license.txt -from __future__ import unicode_literals - -import unittest - -# test_records = frappe.get_test_records('Lab Test UOM') - -class TestLabTestUOM(unittest.TestCase): - pass diff --git a/erpnext/healthcare/doctype/medical_code/__init__.py b/erpnext/healthcare/doctype/medical_code/__init__.py deleted file mode 100644 index e69de29bb2d..00000000000 diff --git a/erpnext/healthcare/doctype/medical_code/medical_code.js b/erpnext/healthcare/doctype/medical_code/medical_code.js deleted file mode 100644 index 0422d774353..00000000000 --- a/erpnext/healthcare/doctype/medical_code/medical_code.js +++ /dev/null @@ -1,5 +0,0 @@ -// Copyright (c) 2017, Frappe Technologies Pvt. Ltd. and contributors -// For license information, please see license.txt - -frappe.ui.form.on('Medical Code', { -}); diff --git a/erpnext/healthcare/doctype/medical_code/medical_code.json b/erpnext/healthcare/doctype/medical_code/medical_code.json deleted file mode 100644 index 5d698309076..00000000000 --- a/erpnext/healthcare/doctype/medical_code/medical_code.json +++ /dev/null @@ -1,69 +0,0 @@ -{ - "actions": [], - "allow_copy": 1, - "allow_import": 1, - "allow_rename": 1, - "beta": 1, - "creation": "2017-06-21 13:02:56.122897", - "doctype": "DocType", - "editable_grid": 1, - "engine": "InnoDB", - "field_order": [ - "medical_code_standard", - "code", - "description" - ], - "fields": [ - { - "fieldname": "medical_code_standard", - "fieldtype": "Link", - "ignore_user_permissions": 1, - "label": "Medical Code Standard", - "options": "Medical Code Standard", - "reqd": 1 - }, - { - "fieldname": "code", - "fieldtype": "Data", - "ignore_xss_filter": 1, - "in_list_view": 1, - "label": "Code", - "reqd": 1, - "unique": 1 - }, - { - "bold": 1, - "fieldname": "description", - "fieldtype": "Small Text", - "ignore_xss_filter": 1, - "in_list_view": 1, - "label": "Description" - } - ], - "links": [], - "modified": "2020-06-29 14:02:30.980032", - "modified_by": "Administrator", - "module": "Healthcare", - "name": "Medical Code", - "owner": "Administrator", - "permissions": [ - { - "create": 1, - "delete": 1, - "email": 1, - "export": 1, - "print": 1, - "read": 1, - "report": 1, - "role": "Physician", - "share": 1, - "write": 1 - } - ], - "quick_entry": 1, - "restrict_to_domain": "Healthcare", - "search_fields": "code, description", - "sort_field": "modified", - "sort_order": "DESC", - "track_changes": 1 -} \ No newline at end of file diff --git a/erpnext/healthcare/doctype/medical_code/medical_code.py b/erpnext/healthcare/doctype/medical_code/medical_code.py deleted file mode 100644 index 4ed3d31e907..00000000000 --- a/erpnext/healthcare/doctype/medical_code/medical_code.py +++ /dev/null @@ -1,12 +0,0 @@ -# -*- coding: utf-8 -*- -# Copyright (c) 2017, Frappe Technologies Pvt. Ltd. and contributors -# For license information, please see license.txt - -from __future__ import unicode_literals - -from frappe.model.document import Document - - -class MedicalCode(Document): - def autoname(self): - self.name = self.medical_code_standard+" "+self.code diff --git a/erpnext/healthcare/doctype/medical_code/test_medical_code.py b/erpnext/healthcare/doctype/medical_code/test_medical_code.py deleted file mode 100644 index 7584b050a65..00000000000 --- a/erpnext/healthcare/doctype/medical_code/test_medical_code.py +++ /dev/null @@ -1,10 +0,0 @@ -# -*- coding: utf-8 -*- -# Copyright (c) 2017, Frappe Technologies Pvt. Ltd. and Contributors -# See license.txt -from __future__ import unicode_literals - -import unittest - - -class TestMedicalCode(unittest.TestCase): - pass diff --git a/erpnext/healthcare/doctype/medical_code_standard/__init__.py b/erpnext/healthcare/doctype/medical_code_standard/__init__.py deleted file mode 100644 index e69de29bb2d..00000000000 diff --git a/erpnext/healthcare/doctype/medical_code_standard/medical_code_standard.js b/erpnext/healthcare/doctype/medical_code_standard/medical_code_standard.js deleted file mode 100644 index 4bf6d3ea160..00000000000 --- a/erpnext/healthcare/doctype/medical_code_standard/medical_code_standard.js +++ /dev/null @@ -1,5 +0,0 @@ -// Copyright (c) 2017, Frappe Technologies Pvt. Ltd. and contributors -// For license information, please see license.txt - -frappe.ui.form.on('Medical Code Standard', { -}); diff --git a/erpnext/healthcare/doctype/medical_code_standard/medical_code_standard.json b/erpnext/healthcare/doctype/medical_code_standard/medical_code_standard.json deleted file mode 100644 index 886938d12ff..00000000000 --- a/erpnext/healthcare/doctype/medical_code_standard/medical_code_standard.json +++ /dev/null @@ -1,94 +0,0 @@ -{ - "allow_copy": 1, - "allow_guest_to_view": 0, - "allow_import": 1, - "allow_rename": 1, - "autoname": "field:medical_code", - "beta": 1, - "creation": "2017-06-21 13:07:00.463176", - "custom": 0, - "docstatus": 0, - "doctype": "DocType", - "document_type": "", - "editable_grid": 1, - "engine": "InnoDB", - "fields": [ - { - "allow_bulk_edit": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "medical_code", - "fieldtype": "Data", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 1, - "in_standard_filter": 0, - "label": "Medical Code", - "length": 0, - "no_copy": 0, - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 1, - "search_index": 0, - "set_only_once": 0, - "unique": 0 - } - ], - "has_web_view": 0, - "hide_heading": 0, - "hide_toolbar": 0, - "idx": 0, - "image_view": 0, - "in_create": 0, - "is_submittable": 0, - "issingle": 0, - "istable": 0, - "max_attachments": 0, - "modified": "2017-08-31 14:15:40.820693", - "modified_by": "Administrator", - "module": "Healthcare", - "name": "Medical Code Standard", - "name_case": "", - "owner": "Administrator", - "permissions": [ - { - "amend": 0, - "apply_user_permissions": 0, - "cancel": 0, - "create": 1, - "delete": 1, - "email": 1, - "export": 1, - "if_owner": 0, - "import": 0, - "permlevel": 0, - "print": 1, - "read": 1, - "report": 1, - "role": "Physician", - "set_user_permissions": 0, - "share": 1, - "submit": 0, - "write": 1 - } - ], - "quick_entry": 1, - "read_only": 0, - "read_only_onload": 0, - "restrict_to_domain": "Healthcare", - "show_name_in_global_search": 0, - "sort_field": "modified", - "sort_order": "DESC", - "track_changes": 1, - "track_seen": 0 -} \ No newline at end of file diff --git a/erpnext/healthcare/doctype/medical_code_standard/medical_code_standard.py b/erpnext/healthcare/doctype/medical_code_standard/medical_code_standard.py deleted file mode 100644 index be0ea8922ed..00000000000 --- a/erpnext/healthcare/doctype/medical_code_standard/medical_code_standard.py +++ /dev/null @@ -1,11 +0,0 @@ -# -*- coding: utf-8 -*- -# Copyright (c) 2017, Frappe Technologies Pvt. Ltd. and contributors -# For license information, please see license.txt - -from __future__ import unicode_literals - -from frappe.model.document import Document - - -class MedicalCodeStandard(Document): - pass diff --git a/erpnext/healthcare/doctype/medical_code_standard/test_medical_code_standard.py b/erpnext/healthcare/doctype/medical_code_standard/test_medical_code_standard.py deleted file mode 100644 index 3b046e360f3..00000000000 --- a/erpnext/healthcare/doctype/medical_code_standard/test_medical_code_standard.py +++ /dev/null @@ -1,10 +0,0 @@ -# -*- coding: utf-8 -*- -# Copyright (c) 2017, Frappe Technologies Pvt. Ltd. and Contributors -# See license.txt -from __future__ import unicode_literals - -import unittest - - -class TestMedicalCodeStandard(unittest.TestCase): - pass diff --git a/erpnext/healthcare/doctype/medical_department/__init__.py b/erpnext/healthcare/doctype/medical_department/__init__.py deleted file mode 100644 index e69de29bb2d..00000000000 diff --git a/erpnext/healthcare/doctype/medical_department/medical_department.js b/erpnext/healthcare/doctype/medical_department/medical_department.js deleted file mode 100644 index 25aeeb85e23..00000000000 --- a/erpnext/healthcare/doctype/medical_department/medical_department.js +++ /dev/null @@ -1,5 +0,0 @@ -// Copyright (c) 2016, ESS LLP and contributors -// For license information, please see license.txt - -frappe.ui.form.on('Medical Department', { -}); diff --git a/erpnext/healthcare/doctype/medical_department/medical_department.json b/erpnext/healthcare/doctype/medical_department/medical_department.json deleted file mode 100644 index 40f14caf729..00000000000 --- a/erpnext/healthcare/doctype/medical_department/medical_department.json +++ /dev/null @@ -1,156 +0,0 @@ -{ - "allow_copy": 1, - "allow_guest_to_view": 0, - "allow_import": 1, - "allow_rename": 1, - "autoname": "field:department", - "beta": 1, - "creation": "2017-02-27 13:38:30.806362", - "custom": 0, - "docstatus": 0, - "doctype": "DocType", - "document_type": "", - "editable_grid": 1, - "engine": "InnoDB", - "fields": [ - { - "allow_bulk_edit": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "department", - "fieldtype": "Data", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 1, - "in_standard_filter": 0, - "label": "Department", - "length": 0, - "no_copy": 0, - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 1, - "search_index": 0, - "set_only_once": 0, - "unique": 0 - } - ], - "has_web_view": 0, - "hide_heading": 0, - "hide_toolbar": 0, - "idx": 0, - "image_view": 0, - "in_create": 0, - "is_submittable": 0, - "issingle": 0, - "istable": 0, - "max_attachments": 0, - "modified": "2017-08-31 13:41:59.611698", - "modified_by": "Administrator", - "module": "Healthcare", - "name": "Medical Department", - "name_case": "", - "owner": "Administrator", - "permissions": [ - { - "amend": 0, - "apply_user_permissions": 0, - "cancel": 0, - "create": 0, - "delete": 0, - "email": 1, - "export": 1, - "if_owner": 0, - "import": 0, - "permlevel": 0, - "print": 1, - "read": 1, - "report": 1, - "role": "Physician", - "set_user_permissions": 0, - "share": 1, - "submit": 0, - "write": 1 - }, - { - "amend": 0, - "apply_user_permissions": 0, - "cancel": 0, - "create": 0, - "delete": 0, - "email": 1, - "export": 1, - "if_owner": 0, - "import": 0, - "permlevel": 0, - "print": 1, - "read": 1, - "report": 1, - "role": "Nursing User", - "set_user_permissions": 0, - "share": 1, - "submit": 0, - "write": 1 - }, - { - "amend": 0, - "apply_user_permissions": 0, - "cancel": 0, - "create": 0, - "delete": 0, - "email": 1, - "export": 1, - "if_owner": 0, - "import": 0, - "permlevel": 0, - "print": 1, - "read": 1, - "report": 1, - "role": "Laboratory User", - "set_user_permissions": 0, - "share": 1, - "submit": 0, - "write": 1 - }, - { - "amend": 0, - "apply_user_permissions": 0, - "cancel": 0, - "create": 1, - "delete": 1, - "email": 1, - "export": 1, - "if_owner": 0, - "import": 0, - "permlevel": 0, - "print": 1, - "read": 1, - "report": 1, - "role": "Healthcare Administrator", - "set_user_permissions": 0, - "share": 1, - "submit": 0, - "write": 1 - } - ], - "quick_entry": 1, - "read_only": 0, - "read_only_onload": 0, - "restrict_to_domain": "Healthcare", - "search_fields": "department", - "show_name_in_global_search": 0, - "sort_field": "modified", - "sort_order": "DESC", - "title_field": "department", - "track_changes": 1, - "track_seen": 0 -} \ No newline at end of file diff --git a/erpnext/healthcare/doctype/medical_department/medical_department.py b/erpnext/healthcare/doctype/medical_department/medical_department.py deleted file mode 100644 index 7be5a1ade34..00000000000 --- a/erpnext/healthcare/doctype/medical_department/medical_department.py +++ /dev/null @@ -1,11 +0,0 @@ -# -*- coding: utf-8 -*- -# Copyright (c) 2015, ESS LLP and contributors -# For license information, please see license.txt - -from __future__ import unicode_literals - -from frappe.model.document import Document - - -class MedicalDepartment(Document): - pass diff --git a/erpnext/healthcare/doctype/medical_department/test_medical_department.py b/erpnext/healthcare/doctype/medical_department/test_medical_department.py deleted file mode 100644 index 6435a23e928..00000000000 --- a/erpnext/healthcare/doctype/medical_department/test_medical_department.py +++ /dev/null @@ -1,11 +0,0 @@ -# -*- coding: utf-8 -*- -# Copyright (c) 2015, ESS LLP and Contributors -# See license.txt -from __future__ import unicode_literals - -import unittest - -# test_records = frappe.get_test_records('Medical Department') - -class TestMedicalDepartment(unittest.TestCase): - pass diff --git a/erpnext/healthcare/doctype/normal_test_result/__init__.py b/erpnext/healthcare/doctype/normal_test_result/__init__.py deleted file mode 100644 index e69de29bb2d..00000000000 diff --git a/erpnext/healthcare/doctype/normal_test_result/normal_test_result.json b/erpnext/healthcare/doctype/normal_test_result/normal_test_result.json deleted file mode 100644 index c8f43d3a54c..00000000000 --- a/erpnext/healthcare/doctype/normal_test_result/normal_test_result.json +++ /dev/null @@ -1,186 +0,0 @@ -{ - "actions": [], - "allow_copy": 1, - "beta": 1, - "creation": "2016-02-22 15:06:08.295224", - "doctype": "DocType", - "document_type": "Document", - "editable_grid": 1, - "engine": "InnoDB", - "field_order": [ - "lab_test_name", - "lab_test_event", - "result_value", - "lab_test_uom", - "secondary_uom_result", - "secondary_uom", - "conversion_factor", - "column_break_10", - "allow_blank", - "normal_range", - "lab_test_comment", - "bold", - "italic", - "underline", - "template", - "require_result_value" - ], - "fields": [ - { - "fieldname": "lab_test_name", - "fieldtype": "Data", - "ignore_xss_filter": 1, - "in_list_view": 1, - "label": "Test Name", - "read_only": 1 - }, - { - "fieldname": "lab_test_event", - "fieldtype": "Data", - "ignore_xss_filter": 1, - "in_list_view": 1, - "label": "Event", - "read_only": 1 - }, - { - "depends_on": "eval:doc.require_result_value", - "fieldname": "result_value", - "fieldtype": "Data", - "ignore_xss_filter": 1, - "in_list_view": 1, - "label": "Result Value" - }, - { - "depends_on": "eval:doc.require_result_value", - "fieldname": "lab_test_uom", - "fieldtype": "Link", - "label": "UOM", - "options": "Lab Test UOM", - "read_only": 1 - }, - { - "depends_on": "eval:doc.require_result_value", - "fieldname": "normal_range", - "fieldtype": "Long Text", - "ignore_xss_filter": 1, - "in_list_view": 1, - "label": "Normal Range", - "read_only": 1 - }, - { - "depends_on": "eval:doc.require_result_value", - "fieldname": "lab_test_comment", - "fieldtype": "Data", - "hidden": 1, - "in_list_view": 1, - "label": "Comment", - "no_copy": 1, - "print_hide": 1, - "report_hide": 1 - }, - { - "fieldname": "template", - "fieldtype": "Link", - "hidden": 1, - "label": "Template", - "options": "Lab Test Template", - "print_hide": 1, - "report_hide": 1 - }, - { - "depends_on": "eval:doc.require_result_value", - "fieldname": "secondary_uom", - "fieldtype": "Link", - "label": "Secondary UOM", - "options": "Lab Test UOM", - "print_hide": 1, - "read_only": 1 - }, - { - "depends_on": "secondary_uom", - "fieldname": "conversion_factor", - "fieldtype": "Float", - "label": "Conversion Factor", - "mandatory_depends_on": "secondary_uom", - "print_hide": 1, - "read_only": 1 - }, - { - "depends_on": "eval:doc.require_result_value && doc.result_value", - "fieldname": "secondary_uom_result", - "fieldtype": "Data", - "label": "Secondary UOM Result", - "no_copy": 1, - "print_hide": 1, - "read_only": 1 - }, - { - "allow_on_submit": 1, - "default": "0", - "depends_on": "eval:doc.require_result_value", - "fieldname": "bold", - "fieldtype": "Check", - "label": "Bold", - "no_copy": 1, - "print_hide": 1, - "report_hide": 1 - }, - { - "allow_on_submit": 1, - "default": "0", - "depends_on": "eval:doc.require_result_value", - "fieldname": "italic", - "fieldtype": "Check", - "label": "Italic", - "no_copy": 1, - "print_hide": 1, - "report_hide": 1 - }, - { - "allow_on_submit": 1, - "default": "0", - "depends_on": "eval:doc.require_result_value", - "fieldname": "underline", - "fieldtype": "Check", - "label": "Underline", - "no_copy": 1, - "print_hide": 1, - "report_hide": 1 - }, - { - "fieldname": "column_break_10", - "fieldtype": "Column Break" - }, - { - "default": "0", - "fieldname": "require_result_value", - "fieldtype": "Check", - "hidden": 1, - "label": "Require Result Value", - "print_hide": 1, - "read_only": 1, - "report_hide": 1 - }, - { - "default": "1", - "depends_on": "eval:doc.require_result_value", - "fieldname": "allow_blank", - "fieldtype": "Check", - "label": "Allow Blank", - "print_hide": 1, - "read_only": 1, - "report_hide": 1 - } - ], - "istable": 1, - "links": [], - "modified": "2020-07-08 16:03:17.522893", - "modified_by": "Administrator", - "module": "Healthcare", - "name": "Normal Test Result", - "owner": "Administrator", - "permissions": [], - "restrict_to_domain": "Healthcare", - "sort_field": "modified", - "sort_order": "DESC" -} \ No newline at end of file diff --git a/erpnext/healthcare/doctype/normal_test_result/normal_test_result.py b/erpnext/healthcare/doctype/normal_test_result/normal_test_result.py deleted file mode 100644 index e72f7269fc3..00000000000 --- a/erpnext/healthcare/doctype/normal_test_result/normal_test_result.py +++ /dev/null @@ -1,11 +0,0 @@ -# -*- coding: utf-8 -*- -# Copyright (c) 2015, ESS and contributors -# For license information, please see license.txt - -from __future__ import unicode_literals - -from frappe.model.document import Document - - -class NormalTestResult(Document): - pass diff --git a/erpnext/healthcare/doctype/normal_test_template/__init__.py b/erpnext/healthcare/doctype/normal_test_template/__init__.py deleted file mode 100644 index e69de29bb2d..00000000000 diff --git a/erpnext/healthcare/doctype/normal_test_template/normal_test_template.json b/erpnext/healthcare/doctype/normal_test_template/normal_test_template.json deleted file mode 100644 index 8dd6476ea87..00000000000 --- a/erpnext/healthcare/doctype/normal_test_template/normal_test_template.json +++ /dev/null @@ -1,84 +0,0 @@ -{ - "actions": [], - "allow_copy": 1, - "beta": 1, - "creation": "2016-02-22 16:09:54.310628", - "doctype": "DocType", - "document_type": "Setup", - "editable_grid": 1, - "engine": "InnoDB", - "field_order": [ - "heading_text", - "lab_test_event", - "allow_blank", - "lab_test_uom", - "secondary_uom", - "conversion_factor", - "column_break_5", - "normal_range" - ], - "fields": [ - { - "fieldname": "heading_text", - "fieldtype": "Heading", - "ignore_xss_filter": 1, - "label": "Test" - }, - { - "fieldname": "lab_test_event", - "fieldtype": "Data", - "ignore_xss_filter": 1, - "in_list_view": 1, - "label": "Event" - }, - { - "fieldname": "lab_test_uom", - "fieldtype": "Link", - "ignore_user_permissions": 1, - "in_list_view": 1, - "label": "UOM", - "options": "Lab Test UOM" - }, - { - "fieldname": "normal_range", - "fieldtype": "Long Text", - "ignore_xss_filter": 1, - "in_list_view": 1, - "label": "Normal Range" - }, - { - "fieldname": "column_break_5", - "fieldtype": "Column Break" - }, - { - "fieldname": "secondary_uom", - "fieldtype": "Link", - "label": "Secondary UOM", - "options": "Lab Test UOM" - }, - { - "depends_on": "secondary_uom", - "fieldname": "conversion_factor", - "fieldtype": "Float", - "label": "Conversion Factor", - "mandatory_depends_on": "secondary_uom" - }, - { - "default": "0", - "fieldname": "allow_blank", - "fieldtype": "Check", - "label": "Allow Blank" - } - ], - "istable": 1, - "links": [], - "modified": "2020-06-23 13:28:40.156224", - "modified_by": "Administrator", - "module": "Healthcare", - "name": "Normal Test Template", - "owner": "Administrator", - "permissions": [], - "restrict_to_domain": "Healthcare", - "sort_field": "modified", - "sort_order": "DESC" -} \ No newline at end of file diff --git a/erpnext/healthcare/doctype/normal_test_template/normal_test_template.py b/erpnext/healthcare/doctype/normal_test_template/normal_test_template.py deleted file mode 100644 index 9df48559cde..00000000000 --- a/erpnext/healthcare/doctype/normal_test_template/normal_test_template.py +++ /dev/null @@ -1,11 +0,0 @@ -# -*- coding: utf-8 -*- -# Copyright (c) 2015, ESS and contributors -# For license information, please see license.txt - -from __future__ import unicode_literals - -from frappe.model.document import Document - - -class NormalTestTemplate(Document): - pass diff --git a/erpnext/healthcare/doctype/organism/__init__.py b/erpnext/healthcare/doctype/organism/__init__.py deleted file mode 100644 index e69de29bb2d..00000000000 diff --git a/erpnext/healthcare/doctype/organism/organism.js b/erpnext/healthcare/doctype/organism/organism.js deleted file mode 100644 index fbcb0942e9d..00000000000 --- a/erpnext/healthcare/doctype/organism/organism.js +++ /dev/null @@ -1,5 +0,0 @@ -// Copyright (c) 2019, Frappe Technologies Pvt. Ltd. and contributors -// For license information, please see license.txt - -frappe.ui.form.on('Organism', { -}); diff --git a/erpnext/healthcare/doctype/organism/organism.json b/erpnext/healthcare/doctype/organism/organism.json deleted file mode 100644 index 88a7686777e..00000000000 --- a/erpnext/healthcare/doctype/organism/organism.json +++ /dev/null @@ -1,152 +0,0 @@ -{ - "allow_copy": 0, - "allow_events_in_timeline": 0, - "allow_guest_to_view": 0, - "allow_import": 0, - "allow_rename": 0, - "autoname": "field:organism", - "beta": 1, - "creation": "2019-09-06 16:29:07.797960", - "custom": 0, - "docstatus": 0, - "doctype": "DocType", - "document_type": "", - "editable_grid": 1, - "engine": "InnoDB", - "fields": [ - { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fetch_if_empty": 0, - "fieldname": "organism", - "fieldtype": "Data", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 1, - "in_standard_filter": 0, - "label": "Organism", - "length": 0, - "no_copy": 0, - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 1, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 1 - }, - { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fetch_if_empty": 0, - "fieldname": "abbr", - "fieldtype": "Data", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "label": "Abbr", - "length": 0, - "no_copy": 0, - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 1 - } - ], - "has_web_view": 0, - "hide_heading": 0, - "hide_toolbar": 0, - "idx": 0, - "image_view": 0, - "in_create": 0, - "is_submittable": 0, - "issingle": 0, - "istable": 0, - "max_attachments": 0, - "modified": "2019-10-04 19:45:33.353753", - "modified_by": "Administrator", - "module": "Healthcare", - "name": "Organism", - "name_case": "", - "owner": "Administrator", - "permissions": [ - { - "amend": 0, - "cancel": 0, - "create": 1, - "delete": 1, - "email": 1, - "export": 1, - "if_owner": 0, - "import": 0, - "permlevel": 0, - "print": 1, - "read": 1, - "report": 1, - "role": "System Manager", - "set_user_permissions": 0, - "share": 1, - "submit": 0, - "write": 1 - }, - { - "amend": 0, - "cancel": 0, - "create": 1, - "delete": 1, - "email": 1, - "export": 1, - "if_owner": 0, - "import": 0, - "permlevel": 0, - "print": 1, - "read": 1, - "report": 1, - "role": "Healthcare Administrator", - "set_user_permissions": 0, - "share": 1, - "submit": 0, - "write": 1 - } - ], - "quick_entry": 1, - "read_only": 0, - "read_only_onload": 0, - "restrict_to_domain": "Healthcare", - "search_fields": "organism, abbr", - "show_name_in_global_search": 0, - "sort_field": "modified", - "sort_order": "DESC", - "title_field": "organism", - "track_changes": 0, - "track_seen": 0, - "track_views": 0 -} \ No newline at end of file diff --git a/erpnext/healthcare/doctype/organism/organism.py b/erpnext/healthcare/doctype/organism/organism.py deleted file mode 100644 index dfb9c0dd0d4..00000000000 --- a/erpnext/healthcare/doctype/organism/organism.py +++ /dev/null @@ -1,11 +0,0 @@ -# -*- coding: utf-8 -*- -# Copyright (c) 2019, Frappe Technologies Pvt. Ltd. and contributors -# For license information, please see license.txt - -from __future__ import unicode_literals - -from frappe.model.document import Document - - -class Organism(Document): - pass diff --git a/erpnext/healthcare/doctype/organism/test_organism.py b/erpnext/healthcare/doctype/organism/test_organism.py deleted file mode 100644 index 9d7ea0ba33d..00000000000 --- a/erpnext/healthcare/doctype/organism/test_organism.py +++ /dev/null @@ -1,10 +0,0 @@ -# -*- coding: utf-8 -*- -# Copyright (c) 2019, Frappe Technologies Pvt. Ltd. and Contributors -# See license.txt -from __future__ import unicode_literals - -import unittest - - -class TestOrganism(unittest.TestCase): - pass diff --git a/erpnext/healthcare/doctype/organism_test_item/__init__.py b/erpnext/healthcare/doctype/organism_test_item/__init__.py deleted file mode 100644 index e69de29bb2d..00000000000 diff --git a/erpnext/healthcare/doctype/organism_test_item/organism_test_item.json b/erpnext/healthcare/doctype/organism_test_item/organism_test_item.json deleted file mode 100644 index 56d0a4d905e..00000000000 --- a/erpnext/healthcare/doctype/organism_test_item/organism_test_item.json +++ /dev/null @@ -1,144 +0,0 @@ -{ - "allow_copy": 0, - "allow_events_in_timeline": 0, - "allow_guest_to_view": 0, - "allow_import": 0, - "allow_rename": 0, - "beta": 1, - "creation": "2019-09-06 16:37:59.698996", - "custom": 0, - "docstatus": 0, - "doctype": "DocType", - "document_type": "", - "editable_grid": 1, - "engine": "InnoDB", - "fields": [ - { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fetch_if_empty": 0, - "fieldname": "organism", - "fieldtype": "Link", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 1, - "in_standard_filter": 0, - "label": "Organism", - "length": 0, - "no_copy": 0, - "options": "Organism", - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 1, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 - }, - { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fetch_if_empty": 0, - "fieldname": "colony_population", - "fieldtype": "Small Text", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 1, - "in_standard_filter": 0, - "label": "Colony Population", - "length": 0, - "no_copy": 0, - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 - }, - { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fetch_if_empty": 0, - "fieldname": "colony_uom", - "fieldtype": "Link", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 1, - "in_standard_filter": 0, - "label": "Colony UOM", - "length": 0, - "no_copy": 0, - "options": "Lab Test UOM", - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 - } - ], - "has_web_view": 0, - "hide_heading": 0, - "hide_toolbar": 0, - "idx": 0, - "image_view": 0, - "in_create": 0, - "is_submittable": 0, - "issingle": 0, - "istable": 1, - "max_attachments": 0, - "modified": "2019-10-04 19:48:04.104234", - "modified_by": "Administrator", - "module": "Healthcare", - "name": "Organism Test Item", - "name_case": "", - "owner": "Administrator", - "permissions": [], - "quick_entry": 0, - "read_only": 0, - "read_only_onload": 0, - "show_name_in_global_search": 0, - "sort_field": "modified", - "sort_order": "DESC", - "track_changes": 0, - "track_seen": 0, - "track_views": 0 -} \ No newline at end of file diff --git a/erpnext/healthcare/doctype/organism_test_item/organism_test_item.py b/erpnext/healthcare/doctype/organism_test_item/organism_test_item.py deleted file mode 100644 index 6bb8e8f4c07..00000000000 --- a/erpnext/healthcare/doctype/organism_test_item/organism_test_item.py +++ /dev/null @@ -1,11 +0,0 @@ -# -*- coding: utf-8 -*- -# Copyright (c) 2019, Frappe Technologies Pvt. Ltd. and contributors -# For license information, please see license.txt - -from __future__ import unicode_literals - -from frappe.model.document import Document - - -class OrganismTestItem(Document): - pass diff --git a/erpnext/healthcare/doctype/organism_test_result/__init__.py b/erpnext/healthcare/doctype/organism_test_result/__init__.py deleted file mode 100644 index e69de29bb2d..00000000000 diff --git a/erpnext/healthcare/doctype/organism_test_result/organism_test_result.json b/erpnext/healthcare/doctype/organism_test_result/organism_test_result.json deleted file mode 100644 index 8b238de4cd3..00000000000 --- a/erpnext/healthcare/doctype/organism_test_result/organism_test_result.json +++ /dev/null @@ -1,144 +0,0 @@ -{ - "allow_copy": 0, - "allow_events_in_timeline": 0, - "allow_guest_to_view": 0, - "allow_import": 0, - "allow_rename": 0, - "beta": 1, - "creation": "2019-09-06 16:37:59.698996", - "custom": 0, - "docstatus": 0, - "doctype": "DocType", - "document_type": "", - "editable_grid": 1, - "engine": "InnoDB", - "fields": [ - { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fetch_if_empty": 0, - "fieldname": "organism", - "fieldtype": "Link", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 1, - "in_standard_filter": 0, - "label": "Organism", - "length": 0, - "no_copy": 0, - "options": "Organism", - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 1, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 - }, - { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fetch_if_empty": 0, - "fieldname": "colony_population", - "fieldtype": "Small Text", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 1, - "in_standard_filter": 0, - "label": "Colony Population", - "length": 0, - "no_copy": 0, - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 - }, - { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fetch_if_empty": 0, - "fieldname": "colony_uom", - "fieldtype": "Link", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 1, - "in_standard_filter": 0, - "label": "Colony UOM", - "length": 0, - "no_copy": 0, - "options": "Lab Test UOM", - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 - } - ], - "has_web_view": 0, - "hide_heading": 0, - "hide_toolbar": 0, - "idx": 0, - "image_view": 0, - "in_create": 0, - "is_submittable": 0, - "issingle": 0, - "istable": 1, - "max_attachments": 0, - "modified": "2019-10-04 19:48:04.104234", - "modified_by": "Administrator", - "module": "Healthcare", - "name": "Organism Test Result", - "name_case": "", - "owner": "Administrator", - "permissions": [], - "quick_entry": 0, - "read_only": 0, - "read_only_onload": 0, - "show_name_in_global_search": 0, - "sort_field": "modified", - "sort_order": "DESC", - "track_changes": 0, - "track_seen": 0, - "track_views": 0 -} \ No newline at end of file diff --git a/erpnext/healthcare/doctype/organism_test_result/organism_test_result.py b/erpnext/healthcare/doctype/organism_test_result/organism_test_result.py deleted file mode 100644 index 3428403e3c0..00000000000 --- a/erpnext/healthcare/doctype/organism_test_result/organism_test_result.py +++ /dev/null @@ -1,11 +0,0 @@ -# -*- coding: utf-8 -*- -# Copyright (c) 2019, Frappe Technologies Pvt. Ltd. and contributors -# For license information, please see license.txt - -from __future__ import unicode_literals - -from frappe.model.document import Document - - -class OrganismTestResult(Document): - pass diff --git a/erpnext/healthcare/doctype/patient/__init__.py b/erpnext/healthcare/doctype/patient/__init__.py deleted file mode 100644 index e69de29bb2d..00000000000 diff --git a/erpnext/healthcare/doctype/patient/patient.js b/erpnext/healthcare/doctype/patient/patient.js deleted file mode 100644 index 9266467155f..00000000000 --- a/erpnext/healthcare/doctype/patient/patient.js +++ /dev/null @@ -1,146 +0,0 @@ -// Copyright (c) 2016, ESS LLP and contributors -// For license information, please see license.txt - -frappe.ui.form.on('Patient', { - refresh: function (frm) { - frm.set_query('patient', 'patient_relation', function () { - return { - filters: [ - ['Patient', 'name', '!=', frm.doc.name] - ] - }; - }); - frm.set_query('customer_group', {'is_group': 0}); - frm.set_query('default_price_list', { 'selling': 1}); - - if (frappe.defaults.get_default('patient_name_by') != 'Naming Series') { - frm.toggle_display('naming_series', false); - } else { - erpnext.toggle_naming_series(); - } - - if (frappe.defaults.get_default('collect_registration_fee') && frm.doc.status == 'Disabled') { - frm.add_custom_button(__('Invoice Patient Registration'), function () { - invoice_registration(frm); - }); - } - - if (frm.doc.patient_name && frappe.user.has_role('Physician')) { - frm.add_custom_button(__('Patient Progress'), function() { - frappe.route_options = {'patient': frm.doc.name}; - frappe.set_route('patient-progress'); - }, __('View')); - - frm.add_custom_button(__('Patient History'), function() { - frappe.route_options = {'patient': frm.doc.name}; - frappe.set_route('patient_history'); - }, __('View')); - } - - frappe.dynamic_link = {doc: frm.doc, fieldname: 'name', doctype: 'Patient'}; - frm.toggle_display(['address_html', 'contact_html'], !frm.is_new()); - - if (!frm.is_new()) { - if ((frappe.user.has_role('Nursing User') || frappe.user.has_role('Physician'))) { - frm.add_custom_button(__('Medical Record'), function () { - create_medical_record(frm); - }, 'Create'); - frm.toggle_enable(['customer'], 0); - } - frappe.contacts.render_address_and_contact(frm); - erpnext.utils.set_party_dashboard_indicators(frm); - } else { - frappe.contacts.clear_address_and_contact(frm); - } - }, - - onload: function (frm) { - if (frm.doc.dob) { - $(frm.fields_dict['age_html'].wrapper).html(`${__('AGE')} : ${get_age(frm.doc.dob)}`); - } else { - $(frm.fields_dict['age_html'].wrapper).html(''); - } - } -}); - -frappe.ui.form.on('Patient', 'dob', function(frm) { - if (frm.doc.dob) { - let today = new Date(); - let birthDate = new Date(frm.doc.dob); - if (today < birthDate) { - frappe.msgprint(__('Please select a valid Date')); - frappe.model.set_value(frm.doctype,frm.docname, 'dob', ''); - } else { - let age_str = get_age(frm.doc.dob); - $(frm.fields_dict['age_html'].wrapper).html(`${__('AGE')} : ${age_str}`); - } - } else { - $(frm.fields_dict['age_html'].wrapper).html(''); - } -}); - -frappe.ui.form.on('Patient Relation', { - patient_relation_add: function(frm){ - frm.fields_dict['patient_relation'].grid.get_field('patient').get_query = function(doc){ - let patient_list = []; - if(!doc.__islocal) patient_list.push(doc.name); - $.each(doc.patient_relation, function(idx, val){ - if (val.patient) patient_list.push(val.patient); - }); - return { filters: [['Patient', 'name', 'not in', patient_list]] }; - }; - } -}); - -let create_medical_record = function (frm) { - frappe.route_options = { - 'patient': frm.doc.name, - 'status': 'Open', - 'reference_doctype': 'Patient Medical Record', - 'reference_owner': frm.doc.owner - }; - frappe.new_doc('Patient Medical Record'); -}; - -let get_age = function (birth) { - let ageMS = Date.parse(Date()) - Date.parse(birth); - let age = new Date(); - age.setTime(ageMS); - let years = age.getFullYear() - 1970; - return years + ' Year(s) ' + age.getMonth() + ' Month(s) ' + age.getDate() + ' Day(s)'; -}; - -let create_vital_signs = function (frm) { - if (!frm.doc.name) { - frappe.throw(__('Please save the patient first')); - } - frappe.route_options = { - 'patient': frm.doc.name, - }; - frappe.new_doc('Vital Signs'); -}; - -let create_encounter = function (frm) { - if (!frm.doc.name) { - frappe.throw(__('Please save the patient first')); - } - frappe.route_options = { - 'patient': frm.doc.name, - }; - frappe.new_doc('Patient Encounter'); -}; - -let invoice_registration = function (frm) { - frappe.call({ - doc: frm.doc, - method: 'invoice_patient_registration', - callback: function(data) { - if (!data.exc) { - if (data.message.invoice) { - frappe.set_route('Form', 'Sales Invoice', data.message.invoice); - } - cur_frm.reload_doc(); - } - } - }); -}; diff --git a/erpnext/healthcare/doctype/patient/patient.json b/erpnext/healthcare/doctype/patient/patient.json deleted file mode 100644 index 4092a6a7681..00000000000 --- a/erpnext/healthcare/doctype/patient/patient.json +++ /dev/null @@ -1,542 +0,0 @@ -{ - "actions": [], - "allow_events_in_timeline": 1, - "allow_import": 1, - "allow_rename": 1, - "autoname": "naming_series:", - "beta": 1, - "creation": "2017-01-23 14:03:49.084370", - "description": "Patient", - "doctype": "DocType", - "document_type": "Document", - "engine": "InnoDB", - "field_order": [ - "basic_info", - "naming_series", - "first_name", - "middle_name", - "last_name", - "patient_name", - "sex", - "blood_group", - "dob", - "age_html", - "image", - "column_break_14", - "status", - "uid", - "inpatient_record", - "inpatient_status", - "report_preference", - "mobile", - "phone", - "email", - "invite_user", - "user_id", - "address_contacts", - "address_html", - "column_break_22", - "contact_html", - "customer_details_section", - "customer", - "customer_group", - "territory", - "column_break_24", - "default_currency", - "default_price_list", - "language", - "personal_and_social_history", - "occupation", - "column_break_25", - "marital_status", - "sb_relation", - "patient_relation", - "allergy_medical_and_surgical_history", - "allergies", - "medication", - "column_break_20", - "medical_history", - "surgical_history", - "risk_factors", - "tobacco_past_use", - "tobacco_current_use", - "alcohol_past_use", - "alcohol_current_use", - "column_break_32", - "surrounding_factors", - "other_risk_factors", - "more_info", - "patient_details" - ], - "fields": [ - { - "fieldname": "basic_info", - "fieldtype": "Section Break", - "label": "Patient Demographics", - "oldfieldtype": "Section Break", - "options": "fa fa-user" - }, - { - "fieldname": "inpatient_status", - "fieldtype": "Select", - "in_preview": 1, - "label": "Inpatient Status", - "no_copy": 1, - "options": "\nAdmission Scheduled\nAdmitted\nDischarge Scheduled", - "read_only": 1 - }, - { - "fieldname": "inpatient_record", - "fieldtype": "Link", - "label": "Inpatient Record", - "no_copy": 1, - "options": "Inpatient Record", - "read_only": 1 - }, - { - "fieldname": "naming_series", - "fieldtype": "Select", - "label": "Series", - "options": "HLC-PAT-.YYYY.-", - "print_hide": 1, - "report_hide": 1, - "set_only_once": 1 - }, - { - "bold": 1, - "fieldname": "patient_name", - "fieldtype": "Data", - "in_global_search": 1, - "in_list_view": 1, - "in_standard_filter": 1, - "label": "Full Name", - "no_copy": 1, - "read_only": 1, - "search_index": 1 - }, - { - "fieldname": "sex", - "fieldtype": "Link", - "in_preview": 1, - "label": "Gender", - "options": "Gender", - "reqd": 1 - }, - { - "bold": 1, - "fieldname": "blood_group", - "fieldtype": "Select", - "in_preview": 1, - "label": "Blood Group", - "no_copy": 1, - "options": "\nA Positive\nA Negative\nAB Positive\nAB Negative\nB Positive\nB Negative\nO Positive\nO Negative" - }, - { - "bold": 1, - "fieldname": "dob", - "fieldtype": "Date", - "in_preview": 1, - "label": "Date of birth", - "no_copy": 1 - }, - { - "fieldname": "age_html", - "fieldtype": "HTML", - "label": "Age", - "no_copy": 1, - "print_hide": 1, - "read_only": 1, - "report_hide": 1 - }, - { - "fieldname": "status", - "fieldtype": "Select", - "in_filter": 1, - "in_list_view": 1, - "label": "Status", - "no_copy": 1, - "options": "Active\nDisabled", - "print_hide": 1, - "read_only": 1 - }, - { - "fieldname": "image", - "fieldtype": "Attach Image", - "hidden": 1, - "in_preview": 1, - "label": "Image", - "no_copy": 1, - "print_hide": 1, - "width": "50%" - }, - { - "fieldname": "column_break_14", - "fieldtype": "Column Break" - }, - { - "description": "If \"Link Customer to Patient\" is checked in Healthcare Settings and an existing Customer is not selected then, a Customer will be created for this Patient for recording transactions in Accounts module.", - "fieldname": "customer", - "fieldtype": "Link", - "ignore_user_permissions": 1, - "label": "Customer", - "no_copy": 1, - "options": "Customer", - "set_only_once": 1 - }, - { - "fieldname": "report_preference", - "fieldtype": "Select", - "label": "Report Preference", - "options": "\nEmail\nPrint" - }, - { - "bold": 1, - "fieldname": "mobile", - "fieldtype": "Data", - "in_list_view": 1, - "in_standard_filter": 1, - "label": "Mobile", - "no_copy": 1, - "options": "Phone" - }, - { - "bold": 1, - "fieldname": "email", - "fieldtype": "Data", - "in_list_view": 1, - "in_standard_filter": 1, - "label": "Email", - "no_copy": 1, - "options": "Email" - }, - { - "fieldname": "phone", - "fieldtype": "Data", - "in_filter": 1, - "label": "Phone", - "no_copy": 1, - "options": "Phone" - }, - { - "collapsible": 1, - "fieldname": "sb_relation", - "fieldtype": "Section Break", - "label": "Patient Relation" - }, - { - "fieldname": "patient_relation", - "fieldtype": "Table", - "label": "Patient Relation", - "options": "Patient Relation" - }, - { - "collapsible": 1, - "fieldname": "allergy_medical_and_surgical_history", - "fieldtype": "Section Break", - "label": "Allergies, Medical and Surgical History" - }, - { - "fieldname": "allergies", - "fieldtype": "Small Text", - "ignore_xss_filter": 1, - "label": "Allergies", - "no_copy": 1 - }, - { - "fieldname": "medication", - "fieldtype": "Small Text", - "ignore_xss_filter": 1, - "label": "Medication", - "no_copy": 1 - }, - { - "fieldname": "column_break_20", - "fieldtype": "Column Break" - }, - { - "fieldname": "medical_history", - "fieldtype": "Small Text", - "ignore_xss_filter": 1, - "label": "Medical History", - "no_copy": 1 - }, - { - "fieldname": "surgical_history", - "fieldtype": "Small Text", - "ignore_xss_filter": 1, - "label": "Surgical History", - "no_copy": 1 - }, - { - "collapsible": 1, - "fieldname": "personal_and_social_history", - "fieldtype": "Section Break", - "label": "Personal and Social History" - }, - { - "fieldname": "occupation", - "fieldtype": "Data", - "ignore_xss_filter": 1, - "label": "Occupation", - "no_copy": 1 - }, - { - "fieldname": "column_break_25", - "fieldtype": "Column Break" - }, - { - "fieldname": "marital_status", - "fieldtype": "Select", - "label": "Marital Status", - "no_copy": 1, - "options": "\nSingle\nMarried\nDivorced\nWidow" - }, - { - "collapsible": 1, - "fieldname": "risk_factors", - "fieldtype": "Section Break", - "label": "Risk Factors" - }, - { - "fieldname": "tobacco_past_use", - "fieldtype": "Data", - "ignore_xss_filter": 1, - "label": "Tobacco Consumption (Past)", - "no_copy": 1 - }, - { - "fieldname": "tobacco_current_use", - "fieldtype": "Data", - "ignore_xss_filter": 1, - "label": "Tobacco Consumption (Present)", - "no_copy": 1 - }, - { - "fieldname": "alcohol_past_use", - "fieldtype": "Data", - "ignore_xss_filter": 1, - "label": "Alcohol Consumption (Past)", - "no_copy": 1 - }, - { - "fieldname": "alcohol_current_use", - "fieldtype": "Data", - "ignore_user_permissions": 1, - "label": "Alcohol Consumption (Present)", - "no_copy": 1 - }, - { - "fieldname": "column_break_32", - "fieldtype": "Column Break" - }, - { - "fieldname": "surrounding_factors", - "fieldtype": "Small Text", - "ignore_xss_filter": 1, - "label": "Occupational Hazards and Environmental Factors", - "no_copy": 1 - }, - { - "fieldname": "other_risk_factors", - "fieldtype": "Small Text", - "ignore_xss_filter": 1, - "label": "Other Risk Factors", - "no_copy": 1 - }, - { - "collapsible": 1, - "collapsible_depends_on": "patient_details", - "fieldname": "more_info", - "fieldtype": "Section Break", - "label": "More Information", - "oldfieldtype": "Section Break", - "options": "fa fa-file-text" - }, - { - "description": "Additional information regarding the patient", - "fieldname": "patient_details", - "fieldtype": "Text", - "ignore_xss_filter": 1, - "label": "Patient Details", - "no_copy": 1 - }, - { - "fieldname": "default_currency", - "fieldtype": "Link", - "label": "Billing Currency", - "options": "Currency" - }, - { - "fieldname": "last_name", - "fieldtype": "Data", - "label": "Last Name", - "no_copy": 1 - }, - { - "fieldname": "first_name", - "fieldtype": "Data", - "label": "First Name", - "no_copy": 1, - "oldfieldtype": "Data", - "reqd": 1 - }, - { - "fieldname": "middle_name", - "fieldtype": "Data", - "label": "Middle Name (optional)", - "no_copy": 1 - }, - { - "collapsible": 1, - "fieldname": "customer_details_section", - "fieldtype": "Section Break", - "label": "Customer Details" - }, - { - "fieldname": "customer_group", - "fieldtype": "Link", - "label": "Customer Group", - "options": "Customer Group" - }, - { - "fieldname": "territory", - "fieldtype": "Link", - "label": "Territory", - "options": "Territory" - }, - { - "fieldname": "column_break_24", - "fieldtype": "Column Break" - }, - { - "fieldname": "default_price_list", - "fieldtype": "Link", - "label": "Default Price List", - "options": "Price List" - }, - { - "fieldname": "language", - "fieldtype": "Link", - "label": "Print Language", - "options": "Language" - }, - { - "depends_on": "eval:!doc.__islocal", - "fieldname": "address_contacts", - "fieldtype": "Section Break", - "label": "Address and Contact", - "options": "fa fa-map-marker" - }, - { - "fieldname": "address_html", - "fieldtype": "HTML", - "label": "Address HTML", - "no_copy": 1, - "read_only": 1 - }, - { - "fieldname": "column_break_22", - "fieldtype": "Column Break" - }, - { - "fieldname": "contact_html", - "fieldtype": "HTML", - "label": "Contact HTML", - "no_copy": 1, - "read_only": 1 - }, - { - "allow_in_quick_entry": 1, - "default": "1", - "fieldname": "invite_user", - "fieldtype": "Check", - "label": "Invite as User", - "no_copy": 1, - "read_only_depends_on": "eval: doc.user_id" - }, - { - "fieldname": "user_id", - "fieldtype": "Read Only", - "label": "User ID", - "no_copy": 1, - "options": "User" - }, - { - "allow_in_quick_entry": 1, - "bold": 1, - "fieldname": "uid", - "fieldtype": "Data", - "in_standard_filter": 1, - "label": "Identification Number (UID)", - "unique": 1 - } - ], - "icon": "fa fa-user", - "image_field": "image", - "links": [], - "max_attachments": 50, - "modified": "2021-03-14 13:21:09.759906", - "modified_by": "Administrator", - "module": "Healthcare", - "name": "Patient", - "name_case": "Title Case", - "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": "Physician", - "share": 1, - "write": 1 - }, - { - "create": 1, - "delete": 1, - "email": 1, - "export": 1, - "print": 1, - "read": 1, - "report": 1, - "role": "Laboratory User", - "share": 1, - "write": 1 - }, - { - "create": 1, - "delete": 1, - "email": 1, - "export": 1, - "print": 1, - "read": 1, - "report": 1, - "role": "Nursing User", - "share": 1, - "write": 1 - } - ], - "quick_entry": 1, - "restrict_to_domain": "Healthcare", - "search_fields": "patient_name,mobile,email,phone,uid", - "show_name_in_global_search": 1, - "sort_field": "modified", - "sort_order": "ASC", - "title_field": "patient_name", - "track_changes": 1 -} \ No newline at end of file diff --git a/erpnext/healthcare/doctype/patient/patient.py b/erpnext/healthcare/doctype/patient/patient.py deleted file mode 100644 index 970c000d008..00000000000 --- a/erpnext/healthcare/doctype/patient/patient.py +++ /dev/null @@ -1,282 +0,0 @@ -# -*- coding: utf-8 -*- -# Copyright (c) 2015, ESS LLP and contributors -# For license information, please see license.txt - -from __future__ import unicode_literals - -import dateutil -import frappe -from frappe import _ -from frappe.contacts.address_and_contact import load_address_and_contact -from frappe.contacts.doctype.contact.contact import get_default_contact -from frappe.model.document import Document -from frappe.model.naming import set_name_by_naming_series -from frappe.utils import cint, cstr, getdate -from frappe.utils.nestedset import get_root_of - -from erpnext import get_default_currency -from erpnext.accounts.party import get_dashboard_info -from erpnext.healthcare.doctype.healthcare_settings.healthcare_settings import ( - get_income_account, - get_receivable_account, - send_registration_sms, -) - - -class Patient(Document): - def onload(self): - '''Load address and contacts in `__onload`''' - load_address_and_contact(self) - self.load_dashboard_info() - - def validate(self): - self.set_full_name() - - def before_insert(self): - self.set_missing_customer_details() - - def after_insert(self): - if frappe.db.get_single_value('Healthcare Settings', 'collect_registration_fee'): - frappe.db.set_value('Patient', self.name, 'status', 'Disabled') - else: - send_registration_sms(self) - self.reload() # self.notify_update() - - def on_update(self): - if frappe.db.get_single_value('Healthcare Settings', 'link_customer_to_patient'): - if self.customer: - customer = frappe.get_doc('Customer', self.customer) - if self.customer_group: - customer.customer_group = self.customer_group - if self.territory: - customer.territory = self.territory - customer.customer_name = self.patient_name - customer.default_price_list = self.default_price_list - customer.default_currency = self.default_currency - customer.language = self.language - customer.ignore_mandatory = True - customer.save(ignore_permissions=True) - else: - create_customer(self) - - self.set_contact() # add or update contact - - if not self.user_id and self.email and self.invite_user: - self.create_website_user() - - def load_dashboard_info(self): - if self.customer: - info = get_dashboard_info('Customer', self.customer, None) - self.set_onload('dashboard_info', info) - - def set_full_name(self): - if self.last_name: - self.patient_name = ' '.join(filter(None, [self.first_name, self.last_name])) - else: - self.patient_name = self.first_name - - def set_missing_customer_details(self): - if not self.customer_group: - self.customer_group = frappe.db.get_single_value('Selling Settings', 'customer_group') or get_root_of('Customer Group') - if not self.territory: - self.territory = frappe.db.get_single_value('Selling Settings', 'territory') or get_root_of('Territory') - if not self.default_price_list: - self.default_price_list = frappe.db.get_single_value('Selling Settings', 'selling_price_list') - - if not self.customer_group or not self.territory or not self.default_price_list: - frappe.msgprint(_('Please set defaults for Customer Group, Territory and Selling Price List in Selling Settings'), alert=True) - - if not self.default_currency: - self.default_currency = get_default_currency() - if not self.language: - self.language = frappe.db.get_single_value('System Settings', 'language') - - def create_website_user(self): - if self.email and not frappe.db.exists('User', self.email): - user = frappe.get_doc({ - 'doctype': 'User', - 'first_name': self.first_name, - 'last_name': self.last_name, - 'email': self.email, - 'user_type': 'Website User', - 'gender': self.sex, - 'phone': self.phone, - 'mobile_no': self.mobile, - 'birth_date': self.dob - }) - user.flags.ignore_permissions = True - user.enabled = True - user.send_welcome_email = True - user.add_roles('Patient') - frappe.db.set_value(self.doctype, self.name, 'user_id', user.name) - - def autoname(self): - patient_name_by = frappe.db.get_single_value('Healthcare Settings', 'patient_name_by') - if patient_name_by == 'Patient Name': - self.name = self.get_patient_name() - else: - set_name_by_naming_series(self) - - def get_patient_name(self): - self.set_full_name() - name = self.patient_name - if frappe.db.get_value('Patient', name): - count = frappe.db.sql("""select ifnull(MAX(CAST(SUBSTRING_INDEX(name, ' ', -1) AS UNSIGNED)), 0) from tabPatient - where name like %s""", "%{0} - %".format(name), as_list=1)[0][0] - count = cint(count) + 1 - return "{0} - {1}".format(name, cstr(count)) - - return name - - @property - def age(self): - if not self.dob: - return - dob = getdate(self.dob) - age = dateutil.relativedelta.relativedelta(getdate(), dob) - return age - - def get_age(self): - age = self.age - if not age: - return - age_str = f'{str(age.years)} {_("Years(s)")} {str(age.months)} {_("Month(s)")} {str(age.days)} {_("Day(s)")}' - return age_str - - @frappe.whitelist() - def invoice_patient_registration(self): - if frappe.db.get_single_value('Healthcare Settings', 'registration_fee'): - company = frappe.defaults.get_user_default('company') - if not company: - company = frappe.db.get_single_value('Global Defaults', 'default_company') - - sales_invoice = make_invoice(self.name, company) - sales_invoice.save(ignore_permissions=True) - frappe.db.set_value('Patient', self.name, 'status', 'Active') - send_registration_sms(self) - - return {'invoice': sales_invoice.name} - - def set_contact(self): - if frappe.db.exists('Dynamic Link', {'parenttype':'Contact', 'link_doctype':'Patient', 'link_name':self.name}): - old_doc = self.get_doc_before_save() - if old_doc.email != self.email or old_doc.mobile != self.mobile or old_doc.phone != self.phone: - self.update_contact() - else: - self.reload() - if self.email or self.mobile or self.phone: - contact = frappe.get_doc({ - 'doctype': 'Contact', - 'first_name': self.first_name, - 'middle_name': self.middle_name, - 'last_name': self.last_name, - 'gender': self.sex, - 'is_primary_contact': 1 - }) - contact.append('links', dict(link_doctype='Patient', link_name=self.name)) - if self.customer: - contact.append('links', dict(link_doctype='Customer', link_name=self.customer)) - - contact.insert(ignore_permissions=True) - self.update_contact(contact) # update email, mobile and phone - - def update_contact(self, contact=None): - if not contact: - contact_name = get_default_contact(self.doctype, self.name) - if contact_name: - contact = frappe.get_doc('Contact', contact_name) - - if contact: - if self.email and self.email != contact.email_id: - for email in contact.email_ids: - email.is_primary = True if email.email_id == self.email else False - contact.add_email(self.email, is_primary=True) - contact.set_primary_email() - - if self.mobile and self.mobile != contact.mobile_no: - for mobile in contact.phone_nos: - mobile.is_primary_mobile_no = True if mobile.phone == self.mobile else False - contact.add_phone(self.mobile, is_primary_mobile_no=True) - contact.set_primary('mobile_no') - - if self.phone and self.phone != contact.phone: - for phone in contact.phone_nos: - phone.is_primary_phone = True if phone.phone == self.phone else False - contact.add_phone(self.phone, is_primary_phone=True) - contact.set_primary('phone') - - contact.flags.ignore_validate = True # disable hook TODO: safe? - contact.save(ignore_permissions=True) - - -def create_customer(doc): - customer = frappe.get_doc({ - 'doctype': 'Customer', - 'customer_name': doc.patient_name, - 'customer_group': doc.customer_group or frappe.db.get_single_value('Selling Settings', 'customer_group'), - 'territory' : doc.territory or frappe.db.get_single_value('Selling Settings', 'territory'), - 'customer_type': 'Individual', - 'default_currency': doc.default_currency, - 'default_price_list': doc.default_price_list, - 'language': doc.language - }).insert(ignore_permissions=True, ignore_mandatory=True) - - frappe.db.set_value('Patient', doc.name, 'customer', customer.name) - frappe.msgprint(_('Customer {0} is created.').format(customer.name), alert=True) - -def make_invoice(patient, company): - uom = frappe.db.exists('UOM', 'Nos') or frappe.db.get_single_value('Stock Settings', 'stock_uom') - sales_invoice = frappe.new_doc('Sales Invoice') - sales_invoice.customer = frappe.db.get_value('Patient', patient, 'customer') - sales_invoice.due_date = getdate() - sales_invoice.company = company - sales_invoice.is_pos = 0 - sales_invoice.debit_to = get_receivable_account(company) - - item_line = sales_invoice.append('items') - item_line.item_name = 'Registration Fee' - item_line.description = 'Registration Fee' - item_line.qty = 1 - item_line.uom = uom - item_line.conversion_factor = 1 - item_line.income_account = get_income_account(None, company) - item_line.rate = frappe.db.get_single_value('Healthcare Settings', 'registration_fee') - item_line.amount = item_line.rate - sales_invoice.set_missing_values() - return sales_invoice - -@frappe.whitelist() -def get_patient_detail(patient): - patient_dict = frappe.db.sql("""select * from tabPatient where name=%s""", (patient), as_dict=1) - if not patient_dict: - frappe.throw(_('Patient not found')) - vital_sign = frappe.db.sql("""select * from `tabVital Signs` where patient=%s - order by signs_date desc limit 1""", (patient), as_dict=1) - - details = patient_dict[0] - if vital_sign: - details.update(vital_sign[0]) - return details - -def get_timeline_data(doctype, name): - ''' - Return Patient's timeline data from medical records - Also include the associated Customer timeline data - ''' - patient_timeline_data = dict(frappe.db.sql(''' - SELECT - unix_timestamp(communication_date), count(*) - FROM - `tabPatient Medical Record` - WHERE - patient=%s - and `communication_date` > date_sub(curdate(), interval 1 year) - GROUP BY communication_date''', name)) - - customer = frappe.db.get_value(doctype, name, 'customer') - if customer: - from erpnext.accounts.party import get_timeline_data - customer_timeline_data = get_timeline_data('Customer', customer) - patient_timeline_data.update(customer_timeline_data) - - return patient_timeline_data diff --git a/erpnext/healthcare/doctype/patient/patient_dashboard.py b/erpnext/healthcare/doctype/patient/patient_dashboard.py deleted file mode 100644 index a388b74f61a..00000000000 --- a/erpnext/healthcare/doctype/patient/patient_dashboard.py +++ /dev/null @@ -1,40 +0,0 @@ -from __future__ import unicode_literals - -from frappe import _ - - -def get_data(): - return { - 'heatmap': True, - 'heatmap_message': _('This is based on transactions against this Patient. See timeline below for details'), - 'fieldname': 'patient', - 'non_standard_fieldnames': { - 'Payment Entry': 'party' - }, - 'transactions': [ - { - 'label': _('Appointments and Encounters'), - 'items': ['Patient Appointment', 'Vital Signs', 'Patient Encounter'] - }, - { - 'label': _('Lab Tests and Vital Signs'), - 'items': ['Lab Test', 'Sample Collection'] - }, - { - 'label': _('Rehab and Physiotherapy'), - 'items': ['Patient Assessment', 'Therapy Session', 'Therapy Plan'] - }, - { - 'label': _('Surgery'), - 'items': ['Clinical Procedure'] - }, - { - 'label': _('Admissions'), - 'items': ['Inpatient Record', 'Inpatient Medication Order'] - }, - { - 'label': _('Billing and Payments'), - 'items': ['Sales Invoice', 'Payment Entry'] - } - ] - } diff --git a/erpnext/healthcare/doctype/patient/test_patient.py b/erpnext/healthcare/doctype/patient/test_patient.py deleted file mode 100644 index 4b8c7326468..00000000000 --- a/erpnext/healthcare/doctype/patient/test_patient.py +++ /dev/null @@ -1,37 +0,0 @@ -# -*- coding: utf-8 -*- -# Copyright (c) 2015, ESS LLP and Contributors -# See license.txt -from __future__ import unicode_literals - -import unittest - -import frappe - -from erpnext.healthcare.doctype.patient_appointment.test_patient_appointment import create_patient - - -class TestPatient(unittest.TestCase): - def test_customer_created(self): - frappe.db.sql("""delete from `tabPatient`""") - frappe.db.set_value('Healthcare Settings', None, 'link_customer_to_patient', 1) - patient = create_patient() - self.assertTrue(frappe.db.get_value('Patient', patient, 'customer')) - - def test_patient_registration(self): - frappe.db.sql("""delete from `tabPatient`""") - settings = frappe.get_single('Healthcare Settings') - settings.collect_registration_fee = 1 - settings.registration_fee = 500 - settings.save() - - patient = create_patient() - patient = frappe.get_doc('Patient', patient) - self.assertEqual(patient.status, 'Disabled') - - # check sales invoice and patient status - result = patient.invoice_patient_registration() - self.assertTrue(frappe.db.exists('Sales Invoice', result.get('invoice'))) - self.assertTrue(patient.status, 'Active') - - settings.collect_registration_fee = 0 - settings.save() diff --git a/erpnext/healthcare/doctype/patient_appointment/__init__.py b/erpnext/healthcare/doctype/patient_appointment/__init__.py deleted file mode 100644 index e69de29bb2d..00000000000 diff --git a/erpnext/healthcare/doctype/patient_appointment/patient_appointment.js b/erpnext/healthcare/doctype/patient_appointment/patient_appointment.js deleted file mode 100644 index 49847d5bc8a..00000000000 --- a/erpnext/healthcare/doctype/patient_appointment/patient_appointment.js +++ /dev/null @@ -1,657 +0,0 @@ -// Copyright (c) 2016, ESS LLP and contributors -// For license information, please see license.txt -frappe.provide('erpnext.queries'); -frappe.ui.form.on('Patient Appointment', { - setup: function(frm) { - frm.custom_make_buttons = { - 'Vital Signs': 'Vital Signs', - 'Patient Encounter': 'Patient Encounter' - }; - }, - - onload: function(frm) { - if (frm.is_new()) { - frm.set_value('appointment_time', null); - frm.disable_save(); - } - }, - - refresh: function(frm) { - frm.set_query('patient', function() { - return { - filters: { 'status': 'Active' } - }; - }); - - frm.set_query('practitioner', function() { - if (frm.doc.department) { - return { - filters: { - 'department': frm.doc.department - } - }; - } - }); - - frm.set_query('service_unit', function() { - return { - query: 'erpnext.controllers.queries.get_healthcare_service_units', - filters: { - company: frm.doc.company, - inpatient_record: frm.doc.inpatient_record - } - }; - }); - - frm.set_query('therapy_plan', function() { - return { - filters: { - 'patient': frm.doc.patient - } - }; - }); - - frm.trigger('set_therapy_type_filter'); - - if (frm.is_new()) { - frm.page.set_primary_action(__('Check Availability'), function() { - if (!frm.doc.patient) { - frappe.msgprint({ - title: __('Not Allowed'), - message: __('Please select Patient first'), - indicator: 'red' - }); - } else { - frappe.call({ - method: 'erpnext.healthcare.doctype.patient_appointment.patient_appointment.check_payment_fields_reqd', - args: { 'patient': frm.doc.patient }, - callback: function(data) { - if (data.message == true) { - if (frm.doc.mode_of_payment && frm.doc.paid_amount) { - check_and_set_availability(frm); - } - if (!frm.doc.mode_of_payment) { - frappe.msgprint({ - title: __('Not Allowed'), - message: __('Please select a Mode of Payment first'), - indicator: 'red' - }); - } - if (!frm.doc.paid_amount) { - frappe.msgprint({ - title: __('Not Allowed'), - message: __('Please set the Paid Amount first'), - indicator: 'red' - }); - } - } else { - check_and_set_availability(frm); - } - } - }); - } - }); - } else { - frm.page.set_primary_action(__('Save'), () => frm.save()); - } - - if (frm.doc.patient) { - frm.add_custom_button(__('Patient History'), function() { - frappe.route_options = { 'patient': frm.doc.patient }; - frappe.set_route('patient_history'); - }, __('View')); - } - - if (frm.doc.status == 'Open' || (frm.doc.status == 'Scheduled' && !frm.doc.__islocal)) { - frm.add_custom_button(__('Cancel'), function() { - update_status(frm, 'Cancelled'); - }); - frm.add_custom_button(__('Reschedule'), function() { - check_and_set_availability(frm); - }); - - if (frm.doc.procedure_template) { - frm.add_custom_button(__('Clinical Procedure'), function() { - frappe.model.open_mapped_doc({ - method: 'erpnext.healthcare.doctype.clinical_procedure.clinical_procedure.make_procedure', - frm: frm, - }); - }, __('Create')); - } else if (frm.doc.therapy_type) { - frm.add_custom_button(__('Therapy Session'), function() { - frappe.model.open_mapped_doc({ - method: 'erpnext.healthcare.doctype.therapy_session.therapy_session.create_therapy_session', - frm: frm, - }) - }, 'Create'); - } else { - frm.add_custom_button(__('Patient Encounter'), function() { - frappe.model.open_mapped_doc({ - method: 'erpnext.healthcare.doctype.patient_appointment.patient_appointment.make_encounter', - frm: frm, - }); - }, __('Create')); - } - - frm.add_custom_button(__('Vital Signs'), function() { - create_vital_signs(frm); - }, __('Create')); - } - }, - - patient: function(frm) { - if (frm.doc.patient) { - frm.trigger('toggle_payment_fields'); - frappe.call({ - method: 'frappe.client.get', - args: { - doctype: 'Patient', - name: frm.doc.patient - }, - callback: function(data) { - let age = null; - if (data.message.dob) { - age = calculate_age(data.message.dob); - } - frappe.model.set_value(frm.doctype, frm.docname, 'patient_age', age); - } - }); - } else { - frm.set_value('patient_name', ''); - frm.set_value('patient_sex', ''); - frm.set_value('patient_age', ''); - frm.set_value('inpatient_record', ''); - } - }, - - practitioner: function(frm) { - if (frm.doc.practitioner) { - frm.events.set_payment_details(frm); - } - }, - - appointment_type: function(frm) { - if (frm.doc.appointment_type) { - frm.events.set_payment_details(frm); - } - }, - - set_payment_details: function(frm) { - frappe.db.get_single_value('Healthcare Settings', 'automate_appointment_invoicing').then(val => { - if (val) { - frappe.call({ - method: 'erpnext.healthcare.utils.get_service_item_and_practitioner_charge', - args: { - doc: frm.doc - }, - callback: function(data) { - if (data.message) { - frappe.model.set_value(frm.doctype, frm.docname, 'paid_amount', data.message.practitioner_charge); - frappe.model.set_value(frm.doctype, frm.docname, 'billing_item', data.message.service_item); - } - } - }); - } - }); - }, - - therapy_plan: function(frm) { - frm.trigger('set_therapy_type_filter'); - }, - - set_therapy_type_filter: function(frm) { - if (frm.doc.therapy_plan) { - frm.call('get_therapy_types').then(r => { - frm.set_query('therapy_type', function() { - return { - filters: { - 'name': ['in', r.message] - } - }; - }); - }); - } - }, - - therapy_type: function(frm) { - if (frm.doc.therapy_type) { - frappe.db.get_value('Therapy Type', frm.doc.therapy_type, 'default_duration', (r) => { - if (r.default_duration) { - frm.set_value('duration', r.default_duration) - } - }); - } - }, - - get_procedure_from_encounter: function(frm) { - get_prescribed_procedure(frm); - }, - - toggle_payment_fields: function(frm) { - frappe.call({ - method: 'erpnext.healthcare.doctype.patient_appointment.patient_appointment.check_payment_fields_reqd', - args: { 'patient': frm.doc.patient }, - callback: function(data) { - if (data.message.fee_validity) { - // if fee validity exists and automated appointment invoicing is enabled, - // show payment fields as non-mandatory - frm.toggle_display('mode_of_payment', 0); - frm.toggle_display('paid_amount', 0); - frm.toggle_display('billing_item', 0); - frm.toggle_reqd('mode_of_payment', 0); - frm.toggle_reqd('paid_amount', 0); - frm.toggle_reqd('billing_item', 0); - } else if (data.message) { - frm.toggle_display('mode_of_payment', 1); - frm.toggle_display('paid_amount', 1); - frm.toggle_display('billing_item', 1); - frm.toggle_reqd('mode_of_payment', 1); - frm.toggle_reqd('paid_amount', 1); - frm.toggle_reqd('billing_item', 1); - } else { - // if automated appointment invoicing is disabled, hide fields - frm.toggle_display('mode_of_payment', data.message ? 1 : 0); - frm.toggle_display('paid_amount', data.message ? 1 : 0); - frm.toggle_display('billing_item', data.message ? 1 : 0); - frm.toggle_reqd('mode_of_payment', data.message ? 1 : 0); - frm.toggle_reqd('paid_amount', data.message ? 1 : 0); - frm.toggle_reqd('billing_item', data.message ? 1 : 0); - } - } - }); - }, - - get_prescribed_therapies: function(frm) { - if (frm.doc.patient) { - frappe.call({ - method: "erpnext.healthcare.doctype.patient_appointment.patient_appointment.get_prescribed_therapies", - args: { patient: frm.doc.patient }, - callback: function(r) { - if (r.message) { - show_therapy_types(frm, r.message); - } else { - frappe.msgprint({ - title: __('Not Therapies Prescribed'), - message: __('There are no Therapies prescribed for Patient {0}', [frm.doc.patient.bold()]), - indicator: 'blue' - }); - } - } - }); - } - } -}); - -let check_and_set_availability = function(frm) { - let selected_slot = null; - let service_unit = null; - let duration = null; - - show_availability(); - - function show_empty_state(practitioner, appointment_date) { - frappe.msgprint({ - title: __('Not Available'), - message: __('Healthcare Practitioner {0} not available on {1}', [practitioner.bold(), appointment_date.bold()]), - indicator: 'red' - }); - } - - function show_availability() { - let selected_practitioner = ''; - let d = new frappe.ui.Dialog({ - title: __('Available slots'), - fields: [ - { fieldtype: 'Link', options: 'Medical Department', reqd: 1, fieldname: 'department', label: 'Medical Department' }, - { fieldtype: 'Column Break' }, - { fieldtype: 'Link', options: 'Healthcare Practitioner', reqd: 1, fieldname: 'practitioner', label: 'Healthcare Practitioner' }, - { fieldtype: 'Column Break' }, - { fieldtype: 'Date', reqd: 1, fieldname: 'appointment_date', label: 'Date' }, - { fieldtype: 'Section Break' }, - { fieldtype: 'HTML', fieldname: 'available_slots' } - - ], - primary_action_label: __('Book'), - primary_action: function() { - frm.set_value('appointment_time', selected_slot); - if (!frm.doc.duration) { - frm.set_value('duration', duration); - } - frm.set_value('practitioner', d.get_value('practitioner')); - frm.set_value('department', d.get_value('department')); - frm.set_value('appointment_date', d.get_value('appointment_date')); - if (service_unit) { - frm.set_value('service_unit', service_unit); - } - d.hide(); - frm.enable_save(); - frm.save(); - d.get_primary_btn().attr('disabled', true); - } - }); - - d.set_values({ - 'department': frm.doc.department, - 'practitioner': frm.doc.practitioner, - 'appointment_date': frm.doc.appointment_date - }); - - d.fields_dict['department'].df.onchange = () => { - d.set_values({ - 'practitioner': '' - }); - let department = d.get_value('department'); - if (department) { - d.fields_dict.practitioner.get_query = function() { - return { - filters: { - 'department': department - } - }; - }; - } - }; - - // disable dialog action initially - d.get_primary_btn().attr('disabled', true); - - // Field Change Handler - - let fd = d.fields_dict; - - d.fields_dict['appointment_date'].df.onchange = () => { - show_slots(d, fd); - }; - d.fields_dict['practitioner'].df.onchange = () => { - if (d.get_value('practitioner') && d.get_value('practitioner') != selected_practitioner) { - selected_practitioner = d.get_value('practitioner'); - show_slots(d, fd); - } - }; - d.show(); - } - - function show_slots(d, fd) { - if (d.get_value('appointment_date') && d.get_value('practitioner')) { - fd.available_slots.html(''); - frappe.call({ - method: 'erpnext.healthcare.doctype.patient_appointment.patient_appointment.get_availability_data', - args: { - practitioner: d.get_value('practitioner'), - date: d.get_value('appointment_date') - }, - callback: (r) => { - let data = r.message; - if (data.slot_details.length > 0) { - let $wrapper = d.fields_dict.available_slots.$wrapper; - - // make buttons for each slot - let slot_html = get_slots(data.slot_details); - - $wrapper - .css('margin-bottom', 0) - .addClass('text-center') - .html(slot_html); - - // highlight button when clicked - $wrapper.on('click', 'button', function() { - let $btn = $(this); - $wrapper.find('button').removeClass('btn-outline-primary'); - $btn.addClass('btn-outline-primary'); - selected_slot = $btn.attr('data-name'); - service_unit = $btn.attr('data-service-unit'); - duration = $btn.attr('data-duration'); - // enable primary action 'Book' - d.get_primary_btn().attr('disabled', null); - }); - - } else { - // fd.available_slots.html('Please select a valid date.'.bold()) - show_empty_state(d.get_value('practitioner'), d.get_value('appointment_date')); - } - }, - freeze: true, - freeze_message: __('Fetching Schedule...') - }); - } else { - fd.available_slots.html(__('Appointment date and Healthcare Practitioner are Mandatory').bold()); - } - } - - function get_slots(slot_details) { - let slot_html = ''; - let appointment_count = 0; - let disabled = false; - let start_str, slot_start_time, slot_end_time, interval, count, count_class, tool_tip, available_slots; - - slot_details.forEach((slot_info) => { - slot_html += `
- ${__('Practitioner Schedule:')} ${slot_info.slot_name}
- ${__('Service Unit:')} ${slot_info.service_unit} `; - - if (slot_info.service_unit_capacity) { - slot_html += `
${__('Maximum Capacity:')} ${slot_info.service_unit_capacity} `; - } - - slot_html += '


'; - - slot_html += slot_info.avail_slot.map(slot => { - appointment_count = 0; - disabled = false; - start_str = slot.from_time; - slot_start_time = moment(slot.from_time, 'HH:mm:ss'); - slot_end_time = moment(slot.to_time, 'HH:mm:ss'); - interval = (slot_end_time - slot_start_time) / 60000 | 0; - - // iterate in all booked appointments, update the start time and duration - slot_info.appointments.forEach((booked) => { - let booked_moment = moment(booked.appointment_time, 'HH:mm:ss'); - let end_time = booked_moment.clone().add(booked.duration, 'minutes'); - - // Deal with 0 duration appointments - if (booked_moment.isSame(slot_start_time) || booked_moment.isBetween(slot_start_time, slot_end_time)) { - if (booked.duration == 0) { - disabled = true; - return false; - } - } - - // Check for overlaps considering appointment duration - if (slot_info.allow_overlap != 1) { - if (slot_start_time.isBefore(end_time) && slot_end_time.isAfter(booked_moment)) { - // There is an overlap - disabled = true; - return false; - } - } else { - if (slot_start_time.isBefore(end_time) && slot_end_time.isAfter(booked_moment)) { - appointment_count++; - } - if (appointment_count >= slot_info.service_unit_capacity) { - // There is an overlap - disabled = true; - return false; - } - } - }); - - if (slot_info.allow_overlap == 1 && slot_info.service_unit_capacity > 1) { - available_slots = slot_info.service_unit_capacity - appointment_count; - count = `${(available_slots > 0 ? available_slots : __('Full'))}`; - count_class = `${(available_slots > 0 ? 'badge-success' : 'badge-danger')}`; - tool_tip =`${available_slots} ${__('slots available for booking')}`; - } - return ` - `; - }).join(""); - - if (slot_info.service_unit_capacity) { - slot_html += `
${__('Each slot indicates the capacity currently available for booking')}`; - } - slot_html += `

`; - }); - - return slot_html; - } -}; - -let get_prescribed_procedure = function(frm) { - if (frm.doc.patient) { - frappe.call({ - method: 'erpnext.healthcare.doctype.patient_appointment.patient_appointment.get_procedure_prescribed', - args: { patient: frm.doc.patient }, - callback: function(r) { - if (r.message && r.message.length) { - show_procedure_templates(frm, r.message); - } else { - frappe.msgprint({ - title: __('Not Found'), - message: __('No Prescribed Procedures found for the selected Patient') - }); - } - } - }); - } else { - frappe.msgprint({ - title: __('Not Allowed'), - message: __('Please select a Patient first') - }); - } -}; - -let show_procedure_templates = function(frm, result) { - let d = new frappe.ui.Dialog({ - title: __('Prescribed Procedures'), - fields: [ - { - fieldtype: 'HTML', fieldname: 'procedure_template' - } - ] - }); - let html_field = d.fields_dict.procedure_template.$wrapper; - html_field.empty(); - $.each(result, function(x, y) { - let row = $(repl('
\ -
%(encounter)s
%(consulting_practitioner)s
%(encounter_date)s
\ -
%(procedure_template)s
%(practitioner)s
%(date)s
\ -

', { - name: y[0], procedure_template: y[1], - encounter: y[2], consulting_practitioner: y[3], encounter_date: y[4], - practitioner: y[5] ? y[5] : '', date: y[6] ? y[6] : '', department: y[7] ? y[7] : '' - })).appendTo(html_field); - row.find("a").click(function() { - frm.doc.procedure_template = $(this).attr('data-procedure-template'); - frm.doc.procedure_prescription = $(this).attr('data-name'); - frm.doc.practitioner = $(this).attr('data-practitioner'); - frm.doc.appointment_date = $(this).attr('data-date'); - frm.doc.department = $(this).attr('data-department'); - refresh_field('procedure_template'); - refresh_field('procedure_prescription'); - refresh_field('appointment_date'); - refresh_field('practitioner'); - refresh_field('department'); - d.hide(); - return false; - }); - }); - if (!result) { - let msg = __('There are no procedure prescribed for ') + frm.doc.patient; - $(repl('
%(msg)s
', { msg: msg })).appendTo(html_field); - } - d.show(); -}; - -let show_therapy_types = function(frm, result) { - var d = new frappe.ui.Dialog({ - title: __('Prescribed Therapies'), - fields: [ - { - fieldtype: 'HTML', fieldname: 'therapy_type' - } - ] - }); - var html_field = d.fields_dict.therapy_type.$wrapper; - $.each(result, function(x, y) { - var row = $(repl('
\ -
%(encounter)s
%(practitioner)s
%(date)s
\ -
%(therapy)s
\ -

', { - therapy: y[0], - name: y[1], encounter: y[2], practitioner: y[3], date: y[4], - department: y[6] ? y[6] : '', therapy_plan: y[5] - })).appendTo(html_field); - - row.find("a").click(function() { - frm.doc.therapy_type = $(this).attr("data-therapy"); - frm.doc.practitioner = $(this).attr("data-practitioner"); - frm.doc.department = $(this).attr("data-department"); - frm.doc.therapy_plan = $(this).attr("data-therapy-plan"); - frm.refresh_field("therapy_type"); - frm.refresh_field("practitioner"); - frm.refresh_field("department"); - frm.refresh_field("therapy-plan"); - frappe.db.get_value('Therapy Type', frm.doc.therapy_type, 'default_duration', (r) => { - if (r.default_duration) { - frm.set_value('duration', r.default_duration) - } - }); - d.hide(); - return false; - }); - }); - d.show(); -}; - -let create_vital_signs = function(frm) { - if (!frm.doc.patient) { - frappe.throw(__('Please select patient')); - } - frappe.route_options = { - 'patient': frm.doc.patient, - 'appointment': frm.doc.name, - 'company': frm.doc.company - }; - frappe.new_doc('Vital Signs'); -}; - -let update_status = function(frm, status) { - let doc = frm.doc; - frappe.confirm(__('Are you sure you want to cancel this appointment?'), - function() { - frappe.call({ - method: 'erpnext.healthcare.doctype.patient_appointment.patient_appointment.update_status', - args: { appointment_id: doc.name, status: status }, - callback: function(data) { - if (!data.exc) { - frm.reload_doc(); - } - } - }); - } - ); -}; - -let calculate_age = function(birth) { - let ageMS = Date.parse(Date()) - Date.parse(birth); - let age = new Date(); - age.setTime(ageMS); - let years = age.getFullYear() - 1970; - return `${years} ${__('Years(s)')} ${age.getMonth()} ${__('Month(s)')} ${age.getDate()} ${__('Day(s)')}`; -}; diff --git a/erpnext/healthcare/doctype/patient_appointment/patient_appointment.json b/erpnext/healthcare/doctype/patient_appointment/patient_appointment.json deleted file mode 100644 index 28d3a6dadf6..00000000000 --- a/erpnext/healthcare/doctype/patient_appointment/patient_appointment.json +++ /dev/null @@ -1,403 +0,0 @@ -{ - "actions": [], - "allow_copy": 1, - "allow_import": 1, - "autoname": "naming_series:", - "beta": 1, - "creation": "2017-05-04 11:52:40.941507", - "doctype": "DocType", - "document_type": "Document", - "engine": "InnoDB", - "field_order": [ - "naming_series", - "title", - "status", - "patient", - "patient_name", - "patient_sex", - "patient_age", - "inpatient_record", - "column_break_1", - "company", - "practitioner", - "practitioner_name", - "department", - "service_unit", - "section_break_12", - "appointment_type", - "duration", - "procedure_template", - "get_procedure_from_encounter", - "procedure_prescription", - "therapy_plan", - "therapy_type", - "get_prescribed_therapies", - "column_break_17", - "appointment_date", - "appointment_time", - "appointment_datetime", - "section_break_16", - "mode_of_payment", - "billing_item", - "invoiced", - "column_break_2", - "paid_amount", - "ref_sales_invoice", - "section_break_3", - "referring_practitioner", - "reminded", - "column_break_36", - "notes" - ], - "fields": [ - { - "fetch_from": "patient.inpatient_record", - "fieldname": "inpatient_record", - "fieldtype": "Link", - "label": "Inpatient Record", - "options": "Inpatient Record", - "read_only": 1 - }, - { - "fieldname": "patient", - "fieldtype": "Link", - "ignore_user_permissions": 1, - "in_list_view": 1, - "in_standard_filter": 1, - "label": "Patient", - "options": "Patient", - "reqd": 1, - "search_index": 1, - "set_only_once": 1 - }, - { - "fieldname": "appointment_type", - "fieldtype": "Link", - "ignore_user_permissions": 1, - "label": "Appointment Type", - "options": "Appointment Type", - "set_only_once": 1 - }, - { - "fetch_from": "appointment_type.default_duration", - "fieldname": "duration", - "fieldtype": "Int", - "in_filter": 1, - "label": "Duration (In Minutes)", - "set_only_once": 1 - }, - { - "fieldname": "column_break_1", - "fieldtype": "Column Break", - "read_only": 1 - }, - { - "depends_on": "eval:!doc.__islocal", - "fieldname": "status", - "fieldtype": "Select", - "in_filter": 1, - "in_list_view": 1, - "label": "Status", - "options": "\nScheduled\nOpen\nClosed\nCancelled", - "read_only": 1, - "search_index": 1 - }, - { - "depends_on": "eval:doc.patient;", - "fieldname": "procedure_template", - "fieldtype": "Link", - "label": "Clinical Procedure Template", - "options": "Clinical Procedure Template", - "set_only_once": 1 - }, - { - "depends_on": "eval:doc.__islocal && doc.patient", - "fieldname": "get_procedure_from_encounter", - "fieldtype": "Button", - "label": "Get Prescribed Clinical Procedures" - }, - { - "fieldname": "procedure_prescription", - "fieldtype": "Link", - "hidden": 1, - "label": "Procedure Prescription", - "no_copy": 1, - "options": "Procedure Prescription", - "print_hide": 1, - "read_only": 1 - }, - { - "fieldname": "service_unit", - "fieldtype": "Link", - "label": "Service Unit", - "options": "Healthcare Service Unit", - "read_only": 1 - }, - { - "depends_on": "eval:doc.practitioner;", - "fieldname": "section_break_12", - "fieldtype": "Section Break", - "label": "Appointment Details" - }, - { - "fieldname": "practitioner", - "fieldtype": "Link", - "in_standard_filter": 1, - "label": "Healthcare Practitioner", - "options": "Healthcare Practitioner", - "reqd": 1, - "search_index": 1, - "set_only_once": 1 - }, - { - "fetch_from": "practitioner.department", - "fieldname": "department", - "fieldtype": "Link", - "ignore_user_permissions": 1, - "in_list_view": 1, - "in_standard_filter": 1, - "label": "Department", - "options": "Medical Department", - "search_index": 1, - "set_only_once": 1 - }, - { - "fieldname": "column_break_17", - "fieldtype": "Column Break" - }, - { - "fieldname": "appointment_date", - "fieldtype": "Date", - "in_list_view": 1, - "in_standard_filter": 1, - "label": "Date", - "read_only": 1, - "reqd": 1, - "search_index": 1 - }, - { - "fieldname": "appointment_time", - "fieldtype": "Time", - "in_list_view": 1, - "label": "Time", - "read_only": 1, - "reqd": 1 - }, - { - "fieldname": "section_break_16", - "fieldtype": "Section Break", - "label": "Payments" - }, - { - "fetch_from": "patient.patient_name", - "fieldname": "patient_name", - "fieldtype": "Data", - "label": "Patient Name", - "read_only": 1 - }, - { - "fetch_from": "patient.sex", - "fieldname": "patient_sex", - "fieldtype": "Link", - "label": "Gender", - "no_copy": 1, - "options": "Gender", - "print_hide": 1, - "read_only": 1, - "report_hide": 1 - }, - { - "fieldname": "patient_age", - "fieldtype": "Data", - "label": "Patient Age", - "read_only": 1 - }, - { - "fieldname": "appointment_datetime", - "fieldtype": "Datetime", - "hidden": 1, - "label": "Appointment Datetime", - "print_hide": 1, - "read_only": 1, - "report_hide": 1, - "search_index": 1 - }, - { - "fieldname": "mode_of_payment", - "fieldtype": "Link", - "label": "Mode of Payment", - "options": "Mode of Payment", - "read_only_depends_on": "invoiced" - }, - { - "fieldname": "paid_amount", - "fieldtype": "Currency", - "label": "Paid Amount", - "read_only_depends_on": "invoiced" - }, - { - "fieldname": "column_break_2", - "fieldtype": "Column Break" - }, - { - "default": "0", - "fieldname": "invoiced", - "fieldtype": "Check", - "label": "Invoiced", - "read_only": 1 - }, - { - "fieldname": "company", - "fieldtype": "Link", - "in_standard_filter": 1, - "label": "Company", - "no_copy": 1, - "options": "Company", - "reqd": 1, - "set_only_once": 1 - }, - { - "collapsible": 1, - "fieldname": "section_break_3", - "fieldtype": "Section Break", - "label": "More Info" - }, - { - "fieldname": "notes", - "fieldtype": "Small Text", - "ignore_xss_filter": 1, - "label": "Notes" - }, - { - "fieldname": "referring_practitioner", - "fieldtype": "Link", - "ignore_user_permissions": 1, - "label": "Referring Practitioner", - "options": "Healthcare Practitioner" - }, - { - "default": "0", - "fieldname": "reminded", - "fieldtype": "Check", - "hidden": 1, - "label": "Reminded", - "print_hide": 1, - "report_hide": 1 - }, - { - "depends_on": "eval:doc.patient && doc.therapy_plan;", - "fieldname": "therapy_type", - "fieldtype": "Link", - "label": "Therapy", - "options": "Therapy Type", - "set_only_once": 1 - }, - { - "depends_on": "eval:doc.patient && doc.therapy_plan && doc.__islocal;", - "fieldname": "get_prescribed_therapies", - "fieldtype": "Button", - "label": "Get Prescribed Therapies" - }, - { - "depends_on": "eval: doc.patient;", - "fieldname": "therapy_plan", - "fieldtype": "Link", - "label": "Therapy Plan", - "options": "Therapy Plan", - "set_only_once": 1 - }, - { - "fieldname": "ref_sales_invoice", - "fieldtype": "Link", - "label": "Reference Sales Invoice", - "options": "Sales Invoice", - "read_only": 1 - }, - { - "fieldname": "naming_series", - "fieldtype": "Select", - "label": "Series", - "options": "HLC-APP-.YYYY.-", - "set_only_once": 1 - }, - { - "fieldname": "billing_item", - "fieldtype": "Link", - "label": "Billing Item", - "options": "Item", - "read_only": 1 - }, - { - "fieldname": "column_break_36", - "fieldtype": "Column Break" - }, - { - "fieldname": "title", - "fieldtype": "Data", - "hidden": 1, - "label": "Title", - "no_copy": 1, - "print_hide": 1, - "read_only": 1 - }, - { - "fetch_from": "practitioner.practitioner_name", - "fieldname": "practitioner_name", - "fieldtype": "Data", - "label": "Practitioner Name", - "read_only": 1 - } - ], - "links": [], - "modified": "2021-08-30 09:00:41.329387", - "modified_by": "Administrator", - "module": "Healthcare", - "name": "Patient Appointment", - "owner": "Administrator", - "permissions": [ - { - "create": 1, - "delete": 1, - "email": 1, - "export": 1, - "print": 1, - "read": 1, - "report": 1, - "role": "Healthcare Administrator", - "share": 1, - "write": 1 - }, - { - "create": 1, - "delete": 1, - "email": 1, - "export": 1, - "print": 1, - "read": 1, - "report": 1, - "role": "Physician", - "share": 1, - "write": 1 - }, - { - "create": 1, - "delete": 1, - "email": 1, - "export": 1, - "print": 1, - "read": 1, - "report": 1, - "role": "Nursing User", - "share": 1, - "write": 1 - } - ], - "restrict_to_domain": "Healthcare", - "search_fields": "patient, practitioner, department, appointment_date, appointment_time", - "show_name_in_global_search": 1, - "sort_field": "modified", - "sort_order": "DESC", - "title_field": "title", - "track_changes": 1, - "track_seen": 1 -} diff --git a/erpnext/healthcare/doctype/patient_appointment/patient_appointment.py b/erpnext/healthcare/doctype/patient_appointment/patient_appointment.py deleted file mode 100755 index dcbcda09d81..00000000000 --- a/erpnext/healthcare/doctype/patient_appointment/patient_appointment.py +++ /dev/null @@ -1,559 +0,0 @@ -# -*- coding: utf-8 -*- -# Copyright (c) 2015, ESS LLP and contributors -# For license information, please see license.txt - -from __future__ import unicode_literals - -import datetime -import json - -import frappe -from frappe import _ -from frappe.core.doctype.sms_settings.sms_settings import send_sms -from frappe.model.document import Document -from frappe.model.mapper import get_mapped_doc -from frappe.utils import flt, get_link_to_form, get_time, getdate - -from erpnext.healthcare.doctype.healthcare_settings.healthcare_settings import ( - get_income_account, - get_receivable_account, -) -from erpnext.healthcare.utils import ( - check_fee_validity, - get_service_item_and_practitioner_charge, - manage_fee_validity, -) -from erpnext.hr.doctype.employee.employee import is_holiday - - -class MaximumCapacityError(frappe.ValidationError): - pass -class OverlapError(frappe.ValidationError): - pass - -class PatientAppointment(Document): - def validate(self): - self.validate_overlaps() - self.validate_service_unit() - self.set_appointment_datetime() - self.validate_customer_created() - self.set_status() - self.set_title() - - def after_insert(self): - self.update_prescription_details() - self.set_payment_details() - invoice_appointment(self) - self.update_fee_validity() - send_confirmation_msg(self) - - def set_title(self): - self.title = _('{0} with {1}').format(self.patient_name or self.patient, - self.practitioner_name or self.practitioner) - - def set_status(self): - today = getdate() - appointment_date = getdate(self.appointment_date) - - # If appointment is created for today set status as Open else Scheduled - if appointment_date == today: - self.status = 'Open' - elif appointment_date > today: - self.status = 'Scheduled' - - def validate_overlaps(self): - end_time = datetime.datetime.combine(getdate(self.appointment_date), get_time(self.appointment_time)) \ - + datetime.timedelta(minutes=flt(self.duration)) - - # all appointments for both patient and practitioner overlapping the duration of this appointment - overlapping_appointments = frappe.db.sql(""" - SELECT - name, practitioner, patient, appointment_time, duration, service_unit - FROM - `tabPatient Appointment` - WHERE - appointment_date=%(appointment_date)s AND name!=%(name)s AND status NOT IN ("Closed", "Cancelled") AND - (practitioner=%(practitioner)s OR patient=%(patient)s) AND - ((appointment_time<%(appointment_time)s AND appointment_time + INTERVAL duration MINUTE>%(appointment_time)s) OR - (appointment_time>%(appointment_time)s AND appointment_time<%(end_time)s) OR - (appointment_time=%(appointment_time)s)) - """, - { - 'appointment_date': self.appointment_date, - 'name': self.name, - 'practitioner': self.practitioner, - 'patient': self.patient, - 'appointment_time': self.appointment_time, - 'end_time':end_time.time() - }, - as_dict = True - ) - - if not overlapping_appointments: - return # No overlaps, nothing to validate! - - if self.service_unit: # validate service unit capacity if overlap enabled - allow_overlap, service_unit_capacity = frappe.get_value('Healthcare Service Unit', self.service_unit, - ['overlap_appointments', 'service_unit_capacity']) - if allow_overlap: - service_unit_appointments = list(filter(lambda appointment: appointment['service_unit'] == self.service_unit and - appointment['patient'] != self.patient, overlapping_appointments)) # if same patient already booked, it should be an overlap - if len(service_unit_appointments) >= (service_unit_capacity or 1): - frappe.throw(_("Not allowed, {} cannot exceed maximum capacity {}") - .format(frappe.bold(self.service_unit), frappe.bold(service_unit_capacity or 1)), MaximumCapacityError) - else: # service_unit_appointments within capacity, remove from overlapping_appointments - overlapping_appointments = [appointment for appointment in overlapping_appointments if appointment not in service_unit_appointments] - - if overlapping_appointments: - frappe.throw(_("Not allowed, cannot overlap appointment {}") - .format(frappe.bold(', '.join([appointment['name'] for appointment in overlapping_appointments]))), OverlapError) - - - def validate_service_unit(self): - if self.inpatient_record and self.service_unit: - from erpnext.healthcare.doctype.inpatient_medication_entry.inpatient_medication_entry import ( - get_current_healthcare_service_unit, - ) - - is_inpatient_occupancy_unit = frappe.db.get_value('Healthcare Service Unit', self.service_unit, - 'inpatient_occupancy') - service_unit = get_current_healthcare_service_unit(self.inpatient_record) - if is_inpatient_occupancy_unit and service_unit != self.service_unit: - msg = _('Patient {0} is not admitted in the service unit {1}').format(frappe.bold(self.patient), frappe.bold(self.service_unit)) + '
' - msg += _('Appointment for service units with Inpatient Occupancy can only be created against the unit where patient has been admitted.') - frappe.throw(msg, title=_('Invalid Healthcare Service Unit')) - - - def set_appointment_datetime(self): - self.appointment_datetime = "%s %s" % (self.appointment_date, self.appointment_time or "00:00:00") - - def set_payment_details(self): - if frappe.db.get_single_value('Healthcare Settings', 'automate_appointment_invoicing'): - details = get_service_item_and_practitioner_charge(self) - self.db_set('billing_item', details.get('service_item')) - if not self.paid_amount: - self.db_set('paid_amount', details.get('practitioner_charge')) - - def validate_customer_created(self): - if frappe.db.get_single_value('Healthcare Settings', 'automate_appointment_invoicing'): - if not frappe.db.get_value('Patient', self.patient, 'customer'): - msg = _("Please set a Customer linked to the Patient") - msg += " {0}".format(self.patient) - frappe.throw(msg, title=_('Customer Not Found')) - - def update_prescription_details(self): - if self.procedure_prescription: - frappe.db.set_value('Procedure Prescription', self.procedure_prescription, 'appointment_booked', 1) - if self.procedure_template: - comments = frappe.db.get_value('Procedure Prescription', self.procedure_prescription, 'comments') - if comments: - frappe.db.set_value('Patient Appointment', self.name, 'notes', comments) - - def update_fee_validity(self): - if not frappe.db.get_single_value('Healthcare Settings', 'enable_free_follow_ups'): - return - - fee_validity = manage_fee_validity(self) - if fee_validity: - frappe.msgprint(_('{0}: {1} has fee validity till {2}').format(self.patient, - frappe.bold(self.patient_name), fee_validity.valid_till)) - - @frappe.whitelist() - def get_therapy_types(self): - if not self.therapy_plan: - return - - therapy_types = [] - doc = frappe.get_doc('Therapy Plan', self.therapy_plan) - for entry in doc.therapy_plan_details: - therapy_types.append(entry.therapy_type) - - return therapy_types - - -@frappe.whitelist() -def check_payment_fields_reqd(patient): - automate_invoicing = frappe.db.get_single_value('Healthcare Settings', 'automate_appointment_invoicing') - free_follow_ups = frappe.db.get_single_value('Healthcare Settings', 'enable_free_follow_ups') - if automate_invoicing: - if free_follow_ups: - fee_validity = frappe.db.exists('Fee Validity', {'patient': patient, 'status': 'Pending'}) - if fee_validity: - return {'fee_validity': fee_validity} - return True - return False - -def invoice_appointment(appointment_doc): - automate_invoicing = frappe.db.get_single_value('Healthcare Settings', 'automate_appointment_invoicing') - appointment_invoiced = frappe.db.get_value('Patient Appointment', appointment_doc.name, 'invoiced') - enable_free_follow_ups = frappe.db.get_single_value('Healthcare Settings', 'enable_free_follow_ups') - if enable_free_follow_ups: - fee_validity = check_fee_validity(appointment_doc) - if fee_validity and fee_validity.status == 'Completed': - fee_validity = None - elif not fee_validity: - if frappe.db.exists('Fee Validity Reference', {'appointment': appointment_doc.name}): - return - else: - fee_validity = None - - if automate_invoicing and not appointment_invoiced and not fee_validity: - create_sales_invoice(appointment_doc) - - -def create_sales_invoice(appointment_doc): - sales_invoice = frappe.new_doc('Sales Invoice') - sales_invoice.patient = appointment_doc.patient - sales_invoice.customer = frappe.get_value('Patient', appointment_doc.patient, 'customer') - sales_invoice.appointment = appointment_doc.name - sales_invoice.due_date = getdate() - sales_invoice.company = appointment_doc.company - sales_invoice.debit_to = get_receivable_account(appointment_doc.company) - - item = sales_invoice.append('items', {}) - item = get_appointment_item(appointment_doc, item) - - # Add payments if payment details are supplied else proceed to create invoice as Unpaid - if appointment_doc.mode_of_payment and appointment_doc.paid_amount: - sales_invoice.is_pos = 1 - payment = sales_invoice.append('payments', {}) - payment.mode_of_payment = appointment_doc.mode_of_payment - payment.amount = appointment_doc.paid_amount - - sales_invoice.set_missing_values(for_validate=True) - sales_invoice.flags.ignore_mandatory = True - sales_invoice.save(ignore_permissions=True) - sales_invoice.submit() - frappe.msgprint(_('Sales Invoice {0} created').format(sales_invoice.name), alert=True) - frappe.db.set_value('Patient Appointment', appointment_doc.name, { - 'invoiced': 1, - 'ref_sales_invoice': sales_invoice.name - }) - - -def check_is_new_patient(patient, name=None): - filters = {'patient': patient, 'status': ('!=','Cancelled')} - if name: - filters['name'] = ('!=', name) - - has_previous_appointment = frappe.db.exists('Patient Appointment', filters) - return not has_previous_appointment - - -def get_appointment_item(appointment_doc, item): - details = get_service_item_and_practitioner_charge(appointment_doc) - charge = appointment_doc.paid_amount or details.get('practitioner_charge') - item.item_code = details.get('service_item') - item.description = _('Consulting Charges: {0}').format(appointment_doc.practitioner) - item.income_account = get_income_account(appointment_doc.practitioner, appointment_doc.company) - item.cost_center = frappe.get_cached_value('Company', appointment_doc.company, 'cost_center') - item.rate = charge - item.amount = charge - item.qty = 1 - item.reference_dt = 'Patient Appointment' - item.reference_dn = appointment_doc.name - return item - - -def cancel_appointment(appointment_id): - appointment = frappe.get_doc('Patient Appointment', appointment_id) - if appointment.invoiced: - sales_invoice = check_sales_invoice_exists(appointment) - if sales_invoice and cancel_sales_invoice(sales_invoice): - msg = _('Appointment {0} and Sales Invoice {1} cancelled').format(appointment.name, sales_invoice.name) - else: - msg = _('Appointment Cancelled. Please review and cancel the invoice {0}').format(sales_invoice.name) - else: - fee_validity = manage_fee_validity(appointment) - msg = _('Appointment Cancelled.') - if fee_validity: - msg += _('Fee Validity {0} updated.').format(fee_validity.name) - - frappe.msgprint(msg) - - -def cancel_sales_invoice(sales_invoice): - if frappe.db.get_single_value('Healthcare Settings', 'automate_appointment_invoicing'): - if len(sales_invoice.items) == 1: - sales_invoice.cancel() - return True - return False - - -def check_sales_invoice_exists(appointment): - sales_invoice = frappe.db.get_value('Sales Invoice Item', { - 'reference_dt': 'Patient Appointment', - 'reference_dn': appointment.name - }, 'parent') - - if sales_invoice: - sales_invoice = frappe.get_doc('Sales Invoice', sales_invoice) - return sales_invoice - return False - - -@frappe.whitelist() -def get_availability_data(date, practitioner): - """ - Get availability data of 'practitioner' on 'date' - :param date: Date to check in schedule - :param practitioner: Name of the practitioner - :return: dict containing a list of available slots, list of appointments and time of appointments - """ - - date = getdate(date) - weekday = date.strftime('%A') - - practitioner_doc = frappe.get_doc('Healthcare Practitioner', practitioner) - - check_employee_wise_availability(date, practitioner_doc) - - if practitioner_doc.practitioner_schedules: - slot_details = get_available_slots(practitioner_doc, date) - else: - frappe.throw(_('{0} does not have a Healthcare Practitioner Schedule. Add it in Healthcare Practitioner master').format( - practitioner), title=_('Practitioner Schedule Not Found')) - - - if not slot_details: - # TODO: return available slots in nearby dates - frappe.throw(_('Healthcare Practitioner not available on {0}').format(weekday), title=_('Not Available')) - - return {'slot_details': slot_details} - - -def check_employee_wise_availability(date, practitioner_doc): - employee = None - if practitioner_doc.employee: - employee = practitioner_doc.employee - elif practitioner_doc.user_id: - employee = frappe.db.get_value('Employee', {'user_id': practitioner_doc.user_id}, 'name') - - if employee: - # check holiday - if is_holiday(employee, date): - frappe.throw(_('{0} is a holiday'.format(date)), title=_('Not Available')) - - # check leave status - leave_record = frappe.db.sql("""select half_day from `tabLeave Application` - where employee = %s and %s between from_date and to_date - and docstatus = 1""", (employee, date), as_dict=True) - if leave_record: - if leave_record[0].half_day: - frappe.throw(_('{0} is on a Half day Leave on {1}').format(practitioner_doc.name, date), title=_('Not Available')) - else: - frappe.throw(_('{0} is on Leave on {1}').format(practitioner_doc.name, date), title=_('Not Available')) - - -def get_available_slots(practitioner_doc, date): - available_slots = slot_details = [] - weekday = date.strftime('%A') - practitioner = practitioner_doc.name - - for schedule_entry in practitioner_doc.practitioner_schedules: - validate_practitioner_schedules(schedule_entry, practitioner) - practitioner_schedule = frappe.get_doc('Practitioner Schedule', schedule_entry.schedule) - - if practitioner_schedule: - available_slots = [] - for time_slot in practitioner_schedule.time_slots: - if weekday == time_slot.day: - available_slots.append(time_slot) - - if available_slots: - appointments = [] - allow_overlap = 0 - service_unit_capacity = 0 - # fetch all appointments to practitioner by service unit - filters = { - 'practitioner': practitioner, - 'service_unit': schedule_entry.service_unit, - 'appointment_date': date, - 'status': ['not in',['Cancelled']] - } - - if schedule_entry.service_unit: - slot_name = f'{schedule_entry.schedule}' - allow_overlap, service_unit_capacity = frappe.get_value('Healthcare Service Unit', schedule_entry.service_unit, ['overlap_appointments', 'service_unit_capacity']) - if not allow_overlap: - # fetch all appointments to service unit - filters.pop('practitioner') - else: - slot_name = schedule_entry.schedule - # fetch all appointments to practitioner without service unit - filters['practitioner'] = practitioner - filters.pop('service_unit') - - appointments = frappe.get_all( - 'Patient Appointment', - filters=filters, - fields=['name', 'appointment_time', 'duration', 'status']) - - slot_details.append({'slot_name': slot_name, 'service_unit': schedule_entry.service_unit, 'avail_slot': available_slots, - 'appointments': appointments, 'allow_overlap': allow_overlap, 'service_unit_capacity': service_unit_capacity}) - - return slot_details - - -def validate_practitioner_schedules(schedule_entry, practitioner): - if schedule_entry.schedule: - if not schedule_entry.service_unit: - frappe.throw(_('Practitioner {0} does not have a Service Unit set against the Practitioner Schedule {1}.').format( - get_link_to_form('Healthcare Practitioner', practitioner), frappe.bold(schedule_entry.schedule)), - title=_('Service Unit Not Found')) - - else: - frappe.throw(_('Practitioner {0} does not have a Practitioner Schedule assigned.').format( - get_link_to_form('Healthcare Practitioner', practitioner)), - title=_('Practitioner Schedule Not Found')) - - -@frappe.whitelist() -def update_status(appointment_id, status): - frappe.db.set_value('Patient Appointment', appointment_id, 'status', status) - appointment_booked = True - if status == 'Cancelled': - appointment_booked = False - cancel_appointment(appointment_id) - - procedure_prescription = frappe.db.get_value('Patient Appointment', appointment_id, 'procedure_prescription') - if procedure_prescription: - frappe.db.set_value('Procedure Prescription', procedure_prescription, 'appointment_booked', appointment_booked) - - -def send_confirmation_msg(doc): - if frappe.db.get_single_value('Healthcare Settings', 'send_appointment_confirmation'): - message = frappe.db.get_single_value('Healthcare Settings', 'appointment_confirmation_msg') - try: - send_message(doc, message) - except Exception: - frappe.log_error(frappe.get_traceback(), _('Appointment Confirmation Message Not Sent')) - frappe.msgprint(_('Appointment Confirmation Message Not Sent'), indicator='orange') - - -@frappe.whitelist() -def make_encounter(source_name, target_doc=None): - doc = get_mapped_doc('Patient Appointment', source_name, { - 'Patient Appointment': { - 'doctype': 'Patient Encounter', - 'field_map': [ - ['appointment', 'name'], - ['patient', 'patient'], - ['practitioner', 'practitioner'], - ['medical_department', 'department'], - ['patient_sex', 'patient_sex'], - ['invoiced', 'invoiced'], - ['company', 'company'] - ] - } - }, target_doc) - return doc - - -def send_appointment_reminder(): - if frappe.db.get_single_value('Healthcare Settings', 'send_appointment_reminder'): - remind_before = datetime.datetime.strptime(frappe.db.get_single_value('Healthcare Settings', 'remind_before'), '%H:%M:%S') - reminder_dt = datetime.datetime.now() + datetime.timedelta( - hours=remind_before.hour, minutes=remind_before.minute, seconds=remind_before.second) - - appointment_list = frappe.db.get_all('Patient Appointment', { - 'appointment_datetime': ['between', (datetime.datetime.now(), reminder_dt)], - 'reminded': 0, - 'status': ['!=', 'Cancelled'] - }) - - for appointment in appointment_list: - doc = frappe.get_doc('Patient Appointment', appointment.name) - message = frappe.db.get_single_value('Healthcare Settings', 'appointment_reminder_msg') - send_message(doc, message) - frappe.db.set_value('Patient Appointment', doc.name, 'reminded', 1) - -def send_message(doc, message): - patient_mobile = frappe.db.get_value('Patient', doc.patient, 'mobile') - if patient_mobile: - context = {'doc': doc, 'alert': doc, 'comments': None} - if doc.get('_comments'): - context['comments'] = json.loads(doc.get('_comments')) - - # jinja to string convertion happens here - message = frappe.render_template(message, context) - number = [patient_mobile] - try: - send_sms(number, message) - except Exception as e: - frappe.msgprint(_('SMS not sent, please check SMS Settings'), alert=True) - -@frappe.whitelist() -def get_events(start, end, filters=None): - """Returns events for Gantt / Calendar view rendering. - - :param start: Start date-time. - :param end: End date-time. - :param filters: Filters (JSON). - """ - from frappe.desk.calendar import get_event_conditions - conditions = get_event_conditions('Patient Appointment', filters) - - data = frappe.db.sql(""" - select - `tabPatient Appointment`.name, `tabPatient Appointment`.patient, - `tabPatient Appointment`.practitioner, `tabPatient Appointment`.status, - `tabPatient Appointment`.duration, - timestamp(`tabPatient Appointment`.appointment_date, `tabPatient Appointment`.appointment_time) as 'start', - `tabAppointment Type`.color - from - `tabPatient Appointment` - left join `tabAppointment Type` on `tabPatient Appointment`.appointment_type=`tabAppointment Type`.name - where - (`tabPatient Appointment`.appointment_date between %(start)s and %(end)s) - and `tabPatient Appointment`.status != 'Cancelled' and `tabPatient Appointment`.docstatus < 2 {conditions}""".format(conditions=conditions), - {"start": start, "end": end}, as_dict=True, update={"allDay": 0}) - - for item in data: - item.end = item.start + datetime.timedelta(minutes = item.duration) - - return data - - -@frappe.whitelist() -def get_procedure_prescribed(patient): - return frappe.db.sql( - """ - SELECT - pp.name, pp.procedure, pp.parent, ct.practitioner, - ct.encounter_date, pp.practitioner, pp.date, pp.department - FROM - `tabPatient Encounter` ct, `tabProcedure Prescription` pp - WHERE - ct.patient=%(patient)s and pp.parent=ct.name and pp.appointment_booked=0 - ORDER BY - ct.creation desc - """, {'patient': patient} - ) - - -@frappe.whitelist() -def get_prescribed_therapies(patient): - return frappe.db.sql( - """ - SELECT - t.therapy_type, t.name, t.parent, e.practitioner, - e.encounter_date, e.therapy_plan, e.medical_department - FROM - `tabPatient Encounter` e, `tabTherapy Plan Detail` t - WHERE - e.patient=%(patient)s and t.parent=e.name - ORDER BY - e.creation desc - """, {'patient': patient} - ) - - -def update_appointment_status(): - # update the status of appointments daily - appointments = frappe.get_all('Patient Appointment', { - 'status': ('not in', ['Closed', 'Cancelled']) - }, as_dict=1) - - for appointment in appointments: - frappe.get_doc('Patient Appointment', appointment.name).set_status() diff --git a/erpnext/healthcare/doctype/patient_appointment/patient_appointment_calendar.js b/erpnext/healthcare/doctype/patient_appointment/patient_appointment_calendar.js deleted file mode 100644 index 2249d2a2059..00000000000 --- a/erpnext/healthcare/doctype/patient_appointment/patient_appointment_calendar.js +++ /dev/null @@ -1,14 +0,0 @@ - -frappe.views.calendar["Patient Appointment"] = { - field_map: { - "start": "start", - "end": "end", - "id": "name", - "title": "patient", - "allDay": "allDay", - "eventColor": "color" - }, - order_by: "appointment_date", - gantt: true, - get_events_method: "erpnext.healthcare.doctype.patient_appointment.patient_appointment.get_events" -}; diff --git a/erpnext/healthcare/doctype/patient_appointment/patient_appointment_dashboard.py b/erpnext/healthcare/doctype/patient_appointment/patient_appointment_dashboard.py deleted file mode 100644 index 43c63c96e6d..00000000000 --- a/erpnext/healthcare/doctype/patient_appointment/patient_appointment_dashboard.py +++ /dev/null @@ -1,18 +0,0 @@ -from __future__ import unicode_literals - -from frappe import _ - - -def get_data(): - return { - 'fieldname': 'appointment', - 'non_standard_fieldnames': { - 'Patient Medical Record': 'reference_name' - }, - 'transactions': [ - { - 'label': _('Consultations'), - 'items': ['Patient Encounter', 'Vital Signs', 'Patient Medical Record'] - } - ] - } diff --git a/erpnext/healthcare/doctype/patient_appointment/patient_appointment_list.js b/erpnext/healthcare/doctype/patient_appointment/patient_appointment_list.js deleted file mode 100644 index 721887b4593..00000000000 --- a/erpnext/healthcare/doctype/patient_appointment/patient_appointment_list.js +++ /dev/null @@ -1,16 +0,0 @@ -/* -(c) ESS 2015-16 -*/ -frappe.listview_settings['Patient Appointment'] = { - filters: [["status", "=", "Open"]], - get_indicator: function(doc) { - var colors = { - "Open": "orange", - "Scheduled": "yellow", - "Closed": "green", - "Cancelled": "red", - "Expired": "grey" - }; - return [__(doc.status), colors[doc.status], "status,=," + doc.status]; - } -}; diff --git a/erpnext/healthcare/doctype/patient_appointment/test_patient_appointment.py b/erpnext/healthcare/doctype/patient_appointment/test_patient_appointment.py deleted file mode 100644 index 8ca30b8cbe0..00000000000 --- a/erpnext/healthcare/doctype/patient_appointment/test_patient_appointment.py +++ /dev/null @@ -1,487 +0,0 @@ -# -*- coding: utf-8 -*- -# Copyright (c) 2015, ESS LLP and Contributors -# See license.txt -from __future__ import unicode_literals - -import unittest - -import frappe -from frappe.utils import add_days, now_datetime, nowdate - -from erpnext.accounts.doctype.pos_profile.test_pos_profile import make_pos_profile -from erpnext.healthcare.doctype.patient_appointment.patient_appointment import ( - check_is_new_patient, - check_payment_fields_reqd, - make_encounter, - update_status, -) - - -class TestPatientAppointment(unittest.TestCase): - def setUp(self): - frappe.db.sql("""delete from `tabPatient Appointment`""") - frappe.db.sql("""delete from `tabFee Validity`""") - frappe.db.sql("""delete from `tabPatient Encounter`""") - make_pos_profile() - frappe.db.sql("""delete from `tabHealthcare Service Unit` where name like '_Test %'""") - frappe.db.sql("""delete from `tabHealthcare Service Unit` where name like '_Test Service Unit Type%'""") - - def test_status(self): - patient, practitioner = create_healthcare_docs() - frappe.db.set_value('Healthcare Settings', None, 'automate_appointment_invoicing', 0) - appointment = create_appointment(patient, practitioner, nowdate()) - self.assertEqual(appointment.status, 'Open') - appointment = create_appointment(patient, practitioner, add_days(nowdate(), 2)) - self.assertEqual(appointment.status, 'Scheduled') - encounter = create_encounter(appointment) - self.assertEqual(frappe.db.get_value('Patient Appointment', appointment.name, 'status'), 'Closed') - encounter.cancel() - self.assertEqual(frappe.db.get_value('Patient Appointment', appointment.name, 'status'), 'Open') - - def test_start_encounter(self): - patient, practitioner = create_healthcare_docs() - frappe.db.set_value('Healthcare Settings', None, 'automate_appointment_invoicing', 1) - appointment = create_appointment(patient, practitioner, add_days(nowdate(), 4), invoice = 1) - appointment.reload() - self.assertEqual(appointment.invoiced, 1) - encounter = make_encounter(appointment.name) - self.assertTrue(encounter) - self.assertEqual(encounter.company, appointment.company) - self.assertEqual(encounter.practitioner, appointment.practitioner) - self.assertEqual(encounter.patient, appointment.patient) - # invoiced flag mapped from appointment - self.assertEqual(encounter.invoiced, frappe.db.get_value('Patient Appointment', appointment.name, 'invoiced')) - - def test_auto_invoicing(self): - patient, practitioner = create_healthcare_docs() - frappe.db.set_value('Healthcare Settings', None, 'enable_free_follow_ups', 0) - frappe.db.set_value('Healthcare Settings', None, 'automate_appointment_invoicing', 0) - appointment = create_appointment(patient, practitioner, nowdate()) - self.assertEqual(frappe.db.get_value('Patient Appointment', appointment.name, 'invoiced'), 0) - - frappe.db.set_value('Healthcare Settings', None, 'automate_appointment_invoicing', 1) - appointment = create_appointment(patient, practitioner, add_days(nowdate(), 2), invoice=1) - self.assertEqual(frappe.db.get_value('Patient Appointment', appointment.name, 'invoiced'), 1) - sales_invoice_name = frappe.db.get_value('Sales Invoice Item', {'reference_dn': appointment.name}, 'parent') - self.assertTrue(sales_invoice_name) - self.assertEqual(frappe.db.get_value('Sales Invoice', sales_invoice_name, 'company'), appointment.company) - self.assertEqual(frappe.db.get_value('Sales Invoice', sales_invoice_name, 'patient'), appointment.patient) - self.assertEqual(frappe.db.get_value('Sales Invoice', sales_invoice_name, 'paid_amount'), appointment.paid_amount) - - def test_auto_invoicing_based_on_department(self): - patient, practitioner = create_healthcare_docs() - medical_department = create_medical_department() - frappe.db.set_value('Healthcare Settings', None, 'enable_free_follow_ups', 0) - frappe.db.set_value('Healthcare Settings', None, 'automate_appointment_invoicing', 1) - appointment_type = create_appointment_type({'medical_department': medical_department}) - - appointment = create_appointment(patient, practitioner, add_days(nowdate(), 2), - invoice=1, appointment_type=appointment_type.name, department=medical_department) - appointment.reload() - - self.assertEqual(appointment.invoiced, 1) - self.assertEqual(appointment.billing_item, 'HLC-SI-001') - self.assertEqual(appointment.paid_amount, 200) - - sales_invoice_name = frappe.db.get_value('Sales Invoice Item', {'reference_dn': appointment.name}, 'parent') - self.assertTrue(sales_invoice_name) - self.assertEqual(frappe.db.get_value('Sales Invoice', sales_invoice_name, 'paid_amount'), appointment.paid_amount) - - def test_auto_invoicing_according_to_appointment_type_charge(self): - patient, practitioner = create_healthcare_docs() - frappe.db.set_value('Healthcare Settings', None, 'enable_free_follow_ups', 0) - frappe.db.set_value('Healthcare Settings', None, 'automate_appointment_invoicing', 1) - - item = create_healthcare_service_items() - items = [{ - 'op_consulting_charge_item': item, - 'op_consulting_charge': 300 - }] - appointment_type = create_appointment_type(args={ - 'name': 'Generic Appointment Type charge', - 'items': items - }) - - appointment = create_appointment(patient, practitioner, add_days(nowdate(), 2), - invoice=1, appointment_type=appointment_type.name) - appointment.reload() - - self.assertEqual(appointment.invoiced, 1) - self.assertEqual(appointment.billing_item, item) - self.assertEqual(appointment.paid_amount, 300) - - sales_invoice_name = frappe.db.get_value('Sales Invoice Item', {'reference_dn': appointment.name}, 'parent') - self.assertTrue(sales_invoice_name) - - def test_appointment_cancel(self): - patient, practitioner = create_healthcare_docs() - frappe.db.set_value('Healthcare Settings', None, 'enable_free_follow_ups', 1) - appointment = create_appointment(patient, practitioner, nowdate()) - fee_validity = frappe.db.get_value('Fee Validity', {'patient': patient, 'practitioner': practitioner}) - # fee validity created - self.assertTrue(fee_validity) - - # first follow up appointment - appointment = create_appointment(patient, practitioner, add_days(nowdate(), 1)) - self.assertEqual(frappe.db.get_value('Fee Validity', fee_validity, 'visited'), 1) - - update_status(appointment.name, 'Cancelled') - # check fee validity updated - self.assertEqual(frappe.db.get_value('Fee Validity', fee_validity, 'visited'), 0) - - frappe.db.set_value('Healthcare Settings', None, 'enable_free_follow_ups', 0) - frappe.db.set_value('Healthcare Settings', None, 'automate_appointment_invoicing', 1) - appointment = create_appointment(patient, practitioner, add_days(nowdate(), 1), invoice=1) - update_status(appointment.name, 'Cancelled') - # check invoice cancelled - sales_invoice_name = frappe.db.get_value('Sales Invoice Item', {'reference_dn': appointment.name}, 'parent') - self.assertEqual(frappe.db.get_value('Sales Invoice', sales_invoice_name, 'status'), 'Cancelled') - - def test_appointment_booking_for_admission_service_unit(self): - from erpnext.healthcare.doctype.inpatient_record.inpatient_record import ( - admit_patient, - discharge_patient, - schedule_discharge, - ) - from erpnext.healthcare.doctype.inpatient_record.test_inpatient_record import ( - create_inpatient, - get_healthcare_service_unit, - mark_invoiced_inpatient_occupancy, - ) - - frappe.db.sql("""delete from `tabInpatient Record`""") - patient, practitioner = create_healthcare_docs() - patient = create_patient() - # Schedule Admission - ip_record = create_inpatient(patient) - ip_record.expected_length_of_stay = 0 - ip_record.save(ignore_permissions = True) - - # Admit - service_unit = get_healthcare_service_unit('_Test Service Unit Ip Occupancy') - admit_patient(ip_record, service_unit, now_datetime()) - - appointment = create_appointment(patient, practitioner, nowdate(), service_unit=service_unit) - self.assertEqual(appointment.service_unit, service_unit) - - # Discharge - schedule_discharge(frappe.as_json({'patient': patient})) - ip_record1 = frappe.get_doc("Inpatient Record", ip_record.name) - mark_invoiced_inpatient_occupancy(ip_record1) - discharge_patient(ip_record1) - - def test_invalid_healthcare_service_unit_validation(self): - from erpnext.healthcare.doctype.inpatient_record.inpatient_record import ( - admit_patient, - discharge_patient, - schedule_discharge, - ) - from erpnext.healthcare.doctype.inpatient_record.test_inpatient_record import ( - create_inpatient, - get_healthcare_service_unit, - mark_invoiced_inpatient_occupancy, - ) - - frappe.db.sql("""delete from `tabInpatient Record`""") - patient, practitioner = create_healthcare_docs() - patient = create_patient() - # Schedule Admission - ip_record = create_inpatient(patient) - ip_record.expected_length_of_stay = 0 - ip_record.save(ignore_permissions = True) - - # Admit - service_unit = get_healthcare_service_unit('_Test Service Unit Ip Occupancy') - admit_patient(ip_record, service_unit, now_datetime()) - - appointment_service_unit = get_healthcare_service_unit('_Test Service Unit Ip Occupancy for Appointment') - appointment = create_appointment(patient, practitioner, nowdate(), service_unit=appointment_service_unit, save=0) - self.assertRaises(frappe.exceptions.ValidationError, appointment.save) - - # Discharge - schedule_discharge(frappe.as_json({'patient': patient})) - ip_record1 = frappe.get_doc("Inpatient Record", ip_record.name) - mark_invoiced_inpatient_occupancy(ip_record1) - discharge_patient(ip_record1) - - def test_payment_should_be_mandatory_for_new_patient_appointment(self): - frappe.db.set_value('Healthcare Settings', None, 'enable_free_follow_ups', 1) - frappe.db.set_value('Healthcare Settings', None, 'automate_appointment_invoicing', 1) - frappe.db.set_value('Healthcare Settings', None, 'max_visits', 3) - frappe.db.set_value('Healthcare Settings', None, 'valid_days', 30) - - patient = create_patient() - assert check_is_new_patient(patient) - payment_required = check_payment_fields_reqd(patient) - assert payment_required is True - - def test_sales_invoice_should_be_generated_for_new_patient_appointment(self): - patient, practitioner = create_healthcare_docs() - frappe.db.set_value('Healthcare Settings', None, 'automate_appointment_invoicing', 1) - invoice_count = frappe.db.count('Sales Invoice') - - assert check_is_new_patient(patient) - create_appointment(patient, practitioner, nowdate()) - new_invoice_count = frappe.db.count('Sales Invoice') - - assert new_invoice_count == invoice_count + 1 - - def test_patient_appointment_should_consider_permissions_while_fetching_appointments(self): - patient, practitioner = create_healthcare_docs() - create_appointment(patient, practitioner, nowdate()) - - patient, new_practitioner = create_healthcare_docs(id=5) - create_appointment(patient, new_practitioner, nowdate()) - - roles = [{"doctype": "Has Role", "role": "Physician"}] - user = create_user(roles=roles) - new_practitioner = frappe.get_doc('Healthcare Practitioner', new_practitioner) - new_practitioner.user_id = user.email - new_practitioner.save() - - frappe.set_user(user.name) - appointments = frappe.get_list('Patient Appointment') - assert len(appointments) == 1 - - frappe.set_user("Administrator") - appointments = frappe.get_list('Patient Appointment') - assert len(appointments) == 2 - - def test_overlap_appointment(self): - from erpnext.healthcare.doctype.patient_appointment.patient_appointment import OverlapError - patient, practitioner = create_healthcare_docs(id=1) - patient_1, practitioner_1 = create_healthcare_docs(id=2) - service_unit = create_service_unit(id=0) - service_unit_1 = create_service_unit(id=1) - appointment = create_appointment(patient, practitioner, nowdate(), service_unit=service_unit) # valid - - # patient and practitioner cannot have overlapping appointments - appointment = create_appointment(patient, practitioner, nowdate(), service_unit=service_unit, save=0) - self.assertRaises(OverlapError, appointment.save) - appointment = create_appointment(patient, practitioner, nowdate(), service_unit=service_unit_1, save=0) # diff service unit - self.assertRaises(OverlapError, appointment.save) - appointment = create_appointment(patient, practitioner, nowdate(), save=0) # with no service unit link - self.assertRaises(OverlapError, appointment.save) - - # patient cannot have overlapping appointments with other practitioners - appointment = create_appointment(patient, practitioner_1, nowdate(), service_unit=service_unit, save=0) - self.assertRaises(OverlapError, appointment.save) - appointment = create_appointment(patient, practitioner_1, nowdate(), service_unit=service_unit_1, save=0) - self.assertRaises(OverlapError, appointment.save) - appointment = create_appointment(patient, practitioner_1, nowdate(), save=0) - self.assertRaises(OverlapError, appointment.save) - - # practitioner cannot have overlapping appointments with other patients - appointment = create_appointment(patient_1, practitioner, nowdate(), service_unit=service_unit, save=0) - self.assertRaises(OverlapError, appointment.save) - appointment = create_appointment(patient_1, practitioner, nowdate(), service_unit=service_unit_1, save=0) - self.assertRaises(OverlapError, appointment.save) - appointment = create_appointment(patient_1, practitioner, nowdate(), save=0) - self.assertRaises(OverlapError, appointment.save) - - def test_service_unit_capacity(self): - from erpnext.healthcare.doctype.patient_appointment.patient_appointment import ( - MaximumCapacityError, - OverlapError, - ) - practitioner = create_practitioner() - capacity = 3 - overlap_service_unit_type = create_service_unit_type(id=10, allow_appointments=1, overlap_appointments=1) - overlap_service_unit = create_service_unit(id=100, service_unit_type=overlap_service_unit_type, service_unit_capacity=capacity) - - for i in range(0, capacity): - patient = create_patient(id=i) - create_appointment(patient, practitioner, nowdate(), service_unit=overlap_service_unit) # valid - appointment = create_appointment(patient, practitioner, nowdate(), service_unit=overlap_service_unit, save=0) # overlap - self.assertRaises(OverlapError, appointment.save) - - patient = create_patient(id=capacity) - appointment = create_appointment(patient, practitioner, nowdate(), service_unit=overlap_service_unit, save=0) - self.assertRaises(MaximumCapacityError, appointment.save) - - -def create_healthcare_docs(id=0): - patient = create_patient(id) - practitioner = create_practitioner(id) - - return patient, practitioner - - -def create_patient(id=0): - if frappe.db.exists('Patient', {'firstname':f'_Test Patient {str(id)}'}): - patient = frappe.db.get_value('Patient', {'first_name': f'_Test Patient {str(id)}'}, ['name']) - return patient - - patient = frappe.new_doc('Patient') - patient.first_name = f'_Test Patient {str(id)}' - patient.sex = 'Female' - patient.save(ignore_permissions=True) - - return patient.name - - -def create_medical_department(id=0): - if frappe.db.exists('Medical Department', f'_Test Medical Department {str(id)}'): - return f'_Test Medical Department {str(id)}' - - medical_department = frappe.new_doc('Medical Department') - medical_department.department = f'_Test Medical Department {str(id)}' - medical_department.save(ignore_permissions=True) - - return medical_department.name - - -def create_practitioner(id=0, medical_department=None): - if frappe.db.exists('Healthcare Practitioner', {'firstname':f'_Test Healthcare Practitioner {str(id)}'}): - practitioner = frappe.db.get_value('Healthcare Practitioner', {'firstname':f'_Test Healthcare Practitioner {str(id)}'}, ['name']) - return practitioner - - practitioner = frappe.new_doc('Healthcare Practitioner') - practitioner.first_name = f'_Test Healthcare Practitioner {str(id)}' - practitioner.gender = 'Female' - practitioner.department = medical_department or create_medical_department(id) - practitioner.op_consulting_charge = 500 - practitioner.inpatient_visit_charge = 500 - practitioner.save(ignore_permissions=True) - - return practitioner.name - - -def create_encounter(appointment): - if appointment: - encounter = frappe.new_doc('Patient Encounter') - encounter.appointment = appointment.name - encounter.patient = appointment.patient - encounter.practitioner = appointment.practitioner - encounter.encounter_date = appointment.appointment_date - encounter.encounter_time = appointment.appointment_time - encounter.company = appointment.company - encounter.save() - encounter.submit() - - return encounter - - -def create_appointment(patient, practitioner, appointment_date, invoice=0, procedure_template=0, - service_unit=None, appointment_type=None, save=1, department=None): - item = create_healthcare_service_items() - frappe.db.set_value('Healthcare Settings', None, 'inpatient_visit_charge_item', item) - frappe.db.set_value('Healthcare Settings', None, 'op_consulting_charge_item', item) - appointment = frappe.new_doc('Patient Appointment') - appointment.patient = patient - appointment.practitioner = practitioner - appointment.department = department or '_Test Medical Department' - appointment.appointment_date = appointment_date - appointment.company = '_Test Company' - appointment.duration = 15 - - if service_unit: - appointment.service_unit = service_unit - if invoice: - appointment.mode_of_payment = 'Cash' - if appointment_type: - appointment.appointment_type = appointment_type - if procedure_template: - appointment.procedure_template = create_clinical_procedure_template().get('name') - if save: - appointment.save(ignore_permissions=True) - - return appointment - - -def create_healthcare_service_items(): - if frappe.db.exists('Item', 'HLC-SI-001'): - return 'HLC-SI-001' - - item = frappe.new_doc('Item') - item.item_code = 'HLC-SI-001' - item.item_name = 'Consulting Charges' - item.item_group = 'Services' - item.is_stock_item = 0 - item.stock_uom = 'Nos' - item.save() - - return item.name - - -def create_clinical_procedure_template(): - if frappe.db.exists('Clinical Procedure Template', 'Knee Surgery and Rehab'): - return frappe.get_doc('Clinical Procedure Template', 'Knee Surgery and Rehab') - - template = frappe.new_doc('Clinical Procedure Template') - template.template = 'Knee Surgery and Rehab' - template.item_code = 'Knee Surgery and Rehab' - template.item_group = 'Services' - template.is_billable = 1 - template.description = 'Knee Surgery and Rehab' - template.rate = 50000 - template.save() - - return template - - -def create_appointment_type(args=None): - if not args: - args = frappe.local.form_dict - - name = args.get('name') or 'Test Appointment Type wise Charge' - - if frappe.db.exists('Appointment Type', name): - return frappe.get_doc('Appointment Type', name) - - else: - item = create_healthcare_service_items() - items = [{ - 'medical_department': args.get('medical_department') or '_Test Medical Department', - 'op_consulting_charge_item': item, - 'op_consulting_charge': 200 - }] - return frappe.get_doc({ - 'doctype': 'Appointment Type', - 'appointment_type': args.get('name') or 'Test Appointment Type wise Charge', - 'default_duration': args.get('default_duration') or 20, - 'color': args.get('color') or '#7575ff', - 'price_list': args.get('price_list') or frappe.db.get_value("Price List", {"selling": 1}), - 'items': args.get('items') or items - }).insert() - -def create_user(email=None, roles=None): - if not email: - email = '{}@frappe.com'.format(frappe.utils.random_string(10)) - user = frappe.db.exists('User', email) - if not user: - user = frappe.get_doc({ - "doctype": "User", - "email": email, - "first_name": "test_user", - "password": "password", - "roles": roles, - }).insert() - return user - - -def create_service_unit_type(id=0, allow_appointments=1, overlap_appointments=0): - if frappe.db.exists('Healthcare Service Unit Type', f'_Test Service Unit Type {str(id)}'): - return f'_Test Service Unit Type {str(id)}' - - service_unit_type = frappe.new_doc('Healthcare Service Unit Type') - service_unit_type.service_unit_type = f'_Test Service Unit Type {str(id)}' - service_unit_type.allow_appointments = allow_appointments - service_unit_type.overlap_appointments = overlap_appointments - service_unit_type.save(ignore_permissions=True) - - return service_unit_type.name - - -def create_service_unit(id=0, service_unit_type=None, service_unit_capacity=0): - if frappe.db.exists('Healthcare Service Unit', f'_Test Service Unit {str(id)}'): - return f'_Test service_unit {str(id)}' - - service_unit = frappe.new_doc('Healthcare Service Unit') - service_unit.is_group = 0 - service_unit.healthcare_service_unit_name= f'_Test Service Unit {str(id)}' - service_unit.service_unit_type = service_unit_type or create_service_unit_type(id) - service_unit.service_unit_capacity = service_unit_capacity - service_unit.save(ignore_permissions=True) - - return service_unit.name diff --git a/erpnext/healthcare/doctype/patient_assessment/__init__.py b/erpnext/healthcare/doctype/patient_assessment/__init__.py deleted file mode 100644 index e69de29bb2d..00000000000 diff --git a/erpnext/healthcare/doctype/patient_assessment/patient_assessment.js b/erpnext/healthcare/doctype/patient_assessment/patient_assessment.js deleted file mode 100644 index f28d32c22c7..00000000000 --- a/erpnext/healthcare/doctype/patient_assessment/patient_assessment.js +++ /dev/null @@ -1,88 +0,0 @@ -// Copyright (c) 2020, Frappe Technologies Pvt. Ltd. and contributors -// For license information, please see license.txt - -frappe.ui.form.on('Patient Assessment', { - refresh: function(frm) { - if (frm.doc.assessment_template) { - frm.trigger('set_score_range'); - } - - if (!frm.doc.__islocal) { - frm.trigger('show_patient_progress'); - } - }, - - assessment_template: function(frm) { - if (frm.doc.assessment_template) { - frappe.call({ - 'method': 'frappe.client.get', - args: { - doctype: 'Patient Assessment Template', - name: frm.doc.assessment_template - }, - callback: function(data) { - frm.doc.assessment_sheet = []; - $.each(data.message.parameters, function(_i, e) { - let entry = frm.add_child('assessment_sheet'); - entry.parameter = e.assessment_parameter; - }); - - frm.set_value('scale_min', data.message.scale_min); - frm.set_value('scale_max', data.message.scale_max); - frm.set_value('assessment_description', data.message.assessment_description); - frm.set_value('total_score', data.message.scale_max * data.message.parameters.length); - frm.trigger('set_score_range'); - refresh_field('assessment_sheet'); - } - }); - } - }, - - set_score_range: function(frm) { - let options = ['']; - for(let i = frm.doc.scale_min; i <= frm.doc.scale_max; i++) { - options.push(i); - } - frm.fields_dict.assessment_sheet.grid.update_docfield_property( - 'score', 'options', options - ); - }, - - calculate_total_score: function(frm, cdt, cdn) { - let row = locals[cdt][cdn]; - let total_score = 0; - $.each(frm.doc.assessment_sheet || [], function(_i, item) { - if (item.score) { - total_score += parseInt(item.score); - } - }); - - frm.set_value('total_score_obtained', total_score); - }, - - show_patient_progress: function(frm) { - let bars = []; - let message = ''; - let added_min = false; - - let title = __('{0} out of {1}', [frm.doc.total_score_obtained, frm.doc.total_score]); - - bars.push({ - 'title': title, - 'width': (frm.doc.total_score_obtained / frm.doc.total_score * 100) + '%', - 'progress_class': 'progress-bar-success' - }); - if (bars[0].width == '0%') { - bars[0].width = '0.5%'; - added_min = 0.5; - } - message = title; - frm.dashboard.add_progress(__('Status'), bars, message); - }, -}); - -frappe.ui.form.on('Patient Assessment Sheet', { - score: function(frm, cdt, cdn) { - frm.events.calculate_total_score(frm, cdt, cdn); - } -}); diff --git a/erpnext/healthcare/doctype/patient_assessment/patient_assessment.json b/erpnext/healthcare/doctype/patient_assessment/patient_assessment.json deleted file mode 100644 index eb0021ff758..00000000000 --- a/erpnext/healthcare/doctype/patient_assessment/patient_assessment.json +++ /dev/null @@ -1,181 +0,0 @@ -{ - "actions": [], - "autoname": "naming_series:", - "creation": "2020-04-19 22:45:12.356209", - "doctype": "DocType", - "editable_grid": 1, - "engine": "InnoDB", - "field_order": [ - "naming_series", - "therapy_session", - "patient", - "assessment_template", - "column_break_4", - "company", - "healthcare_practitioner", - "assessment_datetime", - "assessment_description", - "section_break_7", - "assessment_sheet", - "section_break_9", - "total_score_obtained", - "column_break_11", - "total_score", - "scale_min", - "scale_max", - "amended_from" - ], - "fields": [ - { - "fetch_from": "therapy_session.patient", - "fieldname": "patient", - "fieldtype": "Link", - "in_list_view": 1, - "label": "Patient", - "options": "Patient", - "reqd": 1 - }, - { - "fieldname": "assessment_template", - "fieldtype": "Link", - "in_list_view": 1, - "label": "Assessment Template", - "options": "Patient Assessment Template", - "reqd": 1 - }, - { - "fieldname": "therapy_session", - "fieldtype": "Link", - "label": "Therapy Session", - "options": "Therapy Session" - }, - { - "fieldname": "column_break_4", - "fieldtype": "Column Break" - }, - { - "fetch_from": "therapy_session.practitioner", - "fieldname": "healthcare_practitioner", - "fieldtype": "Link", - "label": "Healthcare Practitioner", - "options": "Healthcare Practitioner" - }, - { - "fieldname": "assessment_datetime", - "fieldtype": "Datetime", - "label": "Assessment Datetime", - "reqd": 1 - }, - { - "fieldname": "section_break_7", - "fieldtype": "Section Break" - }, - { - "fieldname": "assessment_sheet", - "fieldtype": "Table", - "label": "Assessment Sheet", - "options": "Patient Assessment Sheet" - }, - { - "fieldname": "section_break_9", - "fieldtype": "Section Break" - }, - { - "fieldname": "total_score", - "fieldtype": "Int", - "label": "Total Score", - "read_only": 1 - }, - { - "fieldname": "column_break_11", - "fieldtype": "Column Break" - }, - { - "fieldname": "total_score_obtained", - "fieldtype": "Int", - "label": "Total Score Obtained", - "read_only": 1 - }, - { - "fieldname": "scale_min", - "fieldtype": "Int", - "hidden": 1, - "label": "Scale Min", - "read_only": 1 - }, - { - "fieldname": "scale_max", - "fieldtype": "Int", - "hidden": 1, - "label": "Scale Max", - "read_only": 1 - }, - { - "fieldname": "naming_series", - "fieldtype": "Select", - "label": "Naming Series", - "options": "HLC-PA-.YYYY.-" - }, - { - "fieldname": "amended_from", - "fieldtype": "Link", - "label": "Amended From", - "no_copy": 1, - "options": "Patient Assessment", - "print_hide": 1, - "read_only": 1 - }, - { - "fieldname": "assessment_description", - "fieldtype": "Small Text", - "label": "Assessment Description" - }, - { - "fieldname": "company", - "fieldtype": "Link", - "in_standard_filter": 1, - "label": "Company", - "options": "Company" - } - ], - "is_submittable": 1, - "links": [], - "modified": "2020-06-25 00:25:13.208400", - "modified_by": "Administrator", - "module": "Healthcare", - "name": "Patient Assessment", - "owner": "Administrator", - "permissions": [ - { - "cancel": 1, - "create": 1, - "delete": 1, - "email": 1, - "export": 1, - "print": 1, - "read": 1, - "report": 1, - "role": "System Manager", - "share": 1, - "submit": 1, - "write": 1 - }, - { - "cancel": 1, - "create": 1, - "email": 1, - "export": 1, - "print": 1, - "read": 1, - "report": 1, - "role": "Physician", - "share": 1, - "submit": 1, - "write": 1 - } - ], - "sort_field": "modified", - "sort_order": "DESC", - "title_field": "patient", - "track_changes": 1 -} \ No newline at end of file diff --git a/erpnext/healthcare/doctype/patient_assessment/patient_assessment.py b/erpnext/healthcare/doctype/patient_assessment/patient_assessment.py deleted file mode 100644 index 90cb30035d4..00000000000 --- a/erpnext/healthcare/doctype/patient_assessment/patient_assessment.py +++ /dev/null @@ -1,35 +0,0 @@ -# -*- coding: utf-8 -*- -# Copyright (c) 2020, Frappe Technologies Pvt. Ltd. and contributors -# For license information, please see license.txt - -from __future__ import unicode_literals - -import frappe -from frappe.model.document import Document -from frappe.model.mapper import get_mapped_doc - - -class PatientAssessment(Document): - def validate(self): - self.set_total_score() - - def set_total_score(self): - total_score = 0 - for entry in self.assessment_sheet: - total_score += int(entry.score) - self.total_score_obtained = total_score - -@frappe.whitelist() -def create_patient_assessment(source_name, target_doc=None): - doc = get_mapped_doc('Therapy Session', source_name, { - 'Therapy Session': { - 'doctype': 'Patient Assessment', - 'field_map': [ - ['therapy_session', 'name'], - ['patient', 'patient'], - ['practitioner', 'practitioner'] - ] - } - }, target_doc) - - return doc diff --git a/erpnext/healthcare/doctype/patient_assessment/test_patient_assessment.py b/erpnext/healthcare/doctype/patient_assessment/test_patient_assessment.py deleted file mode 100644 index 0ffbd1f5049..00000000000 --- a/erpnext/healthcare/doctype/patient_assessment/test_patient_assessment.py +++ /dev/null @@ -1,11 +0,0 @@ -# -*- coding: utf-8 -*- -# Copyright (c) 2020, Frappe Technologies Pvt. Ltd. and Contributors -# See license.txt -from __future__ import unicode_literals - -# import frappe -import unittest - - -class TestPatientAssessment(unittest.TestCase): - pass diff --git a/erpnext/healthcare/doctype/patient_assessment_detail/__init__.py b/erpnext/healthcare/doctype/patient_assessment_detail/__init__.py deleted file mode 100644 index e69de29bb2d..00000000000 diff --git a/erpnext/healthcare/doctype/patient_assessment_detail/patient_assessment_detail.json b/erpnext/healthcare/doctype/patient_assessment_detail/patient_assessment_detail.json deleted file mode 100644 index 179f441044e..00000000000 --- a/erpnext/healthcare/doctype/patient_assessment_detail/patient_assessment_detail.json +++ /dev/null @@ -1,32 +0,0 @@ -{ - "actions": [], - "creation": "2020-04-19 19:33:00.115395", - "doctype": "DocType", - "editable_grid": 1, - "engine": "InnoDB", - "field_order": [ - "assessment_parameter" - ], - "fields": [ - { - "fieldname": "assessment_parameter", - "fieldtype": "Link", - "in_list_view": 1, - "label": "Assessment Parameter", - "options": "Patient Assessment Parameter", - "reqd": 1 - } - ], - "istable": 1, - "links": [], - "modified": "2020-04-19 19:33:00.115395", - "modified_by": "Administrator", - "module": "Healthcare", - "name": "Patient Assessment Detail", - "owner": "Administrator", - "permissions": [], - "quick_entry": 1, - "sort_field": "modified", - "sort_order": "DESC", - "track_changes": 1 -} \ No newline at end of file diff --git a/erpnext/healthcare/doctype/patient_assessment_detail/patient_assessment_detail.py b/erpnext/healthcare/doctype/patient_assessment_detail/patient_assessment_detail.py deleted file mode 100644 index 4da679b8892..00000000000 --- a/erpnext/healthcare/doctype/patient_assessment_detail/patient_assessment_detail.py +++ /dev/null @@ -1,12 +0,0 @@ -# -*- coding: utf-8 -*- -# Copyright (c) 2020, Frappe Technologies Pvt. Ltd. and contributors -# For license information, please see license.txt - -from __future__ import unicode_literals - -# import frappe -from frappe.model.document import Document - - -class PatientAssessmentDetail(Document): - pass diff --git a/erpnext/healthcare/doctype/patient_assessment_parameter/__init__.py b/erpnext/healthcare/doctype/patient_assessment_parameter/__init__.py deleted file mode 100644 index e69de29bb2d..00000000000 diff --git a/erpnext/healthcare/doctype/patient_assessment_parameter/patient_assessment_parameter.js b/erpnext/healthcare/doctype/patient_assessment_parameter/patient_assessment_parameter.js deleted file mode 100644 index 2c5d270d575..00000000000 --- a/erpnext/healthcare/doctype/patient_assessment_parameter/patient_assessment_parameter.js +++ /dev/null @@ -1,8 +0,0 @@ -// Copyright (c) 2020, Frappe Technologies Pvt. Ltd. and contributors -// For license information, please see license.txt - -frappe.ui.form.on('Patient Assessment Parameter', { - // refresh: function(frm) { - - // } -}); diff --git a/erpnext/healthcare/doctype/patient_assessment_parameter/patient_assessment_parameter.json b/erpnext/healthcare/doctype/patient_assessment_parameter/patient_assessment_parameter.json deleted file mode 100644 index 098bdefea70..00000000000 --- a/erpnext/healthcare/doctype/patient_assessment_parameter/patient_assessment_parameter.json +++ /dev/null @@ -1,45 +0,0 @@ -{ - "actions": [], - "autoname": "field:assessment_parameter", - "creation": "2020-04-15 14:34:46.551042", - "doctype": "DocType", - "editable_grid": 1, - "engine": "InnoDB", - "field_order": [ - "assessment_parameter" - ], - "fields": [ - { - "fieldname": "assessment_parameter", - "fieldtype": "Data", - "in_list_view": 1, - "label": "Assessment Parameter", - "reqd": 1, - "unique": 1 - } - ], - "links": [], - "modified": "2020-04-20 09:22:19.135196", - "modified_by": "Administrator", - "module": "Healthcare", - "name": "Patient Assessment Parameter", - "owner": "Administrator", - "permissions": [ - { - "create": 1, - "delete": 1, - "email": 1, - "export": 1, - "print": 1, - "read": 1, - "report": 1, - "role": "System Manager", - "share": 1, - "write": 1 - } - ], - "quick_entry": 1, - "sort_field": "modified", - "sort_order": "DESC", - "track_changes": 1 -} \ No newline at end of file diff --git a/erpnext/healthcare/doctype/patient_assessment_parameter/patient_assessment_parameter.py b/erpnext/healthcare/doctype/patient_assessment_parameter/patient_assessment_parameter.py deleted file mode 100644 index 783c5378481..00000000000 --- a/erpnext/healthcare/doctype/patient_assessment_parameter/patient_assessment_parameter.py +++ /dev/null @@ -1,12 +0,0 @@ -# -*- coding: utf-8 -*- -# Copyright (c) 2020, Frappe Technologies Pvt. Ltd. and contributors -# For license information, please see license.txt - -from __future__ import unicode_literals - -# import frappe -from frappe.model.document import Document - - -class PatientAssessmentParameter(Document): - pass diff --git a/erpnext/healthcare/doctype/patient_assessment_parameter/test_patient_assessment_parameter.py b/erpnext/healthcare/doctype/patient_assessment_parameter/test_patient_assessment_parameter.py deleted file mode 100644 index f06fffb1ef4..00000000000 --- a/erpnext/healthcare/doctype/patient_assessment_parameter/test_patient_assessment_parameter.py +++ /dev/null @@ -1,11 +0,0 @@ -# -*- coding: utf-8 -*- -# Copyright (c) 2020, Frappe Technologies Pvt. Ltd. and Contributors -# See license.txt -from __future__ import unicode_literals - -# import frappe -import unittest - - -class TestPatientAssessmentParameter(unittest.TestCase): - pass diff --git a/erpnext/healthcare/doctype/patient_assessment_sheet/__init__.py b/erpnext/healthcare/doctype/patient_assessment_sheet/__init__.py deleted file mode 100644 index e69de29bb2d..00000000000 diff --git a/erpnext/healthcare/doctype/patient_assessment_sheet/patient_assessment_sheet.json b/erpnext/healthcare/doctype/patient_assessment_sheet/patient_assessment_sheet.json deleted file mode 100644 index 64e4aef7cf0..00000000000 --- a/erpnext/healthcare/doctype/patient_assessment_sheet/patient_assessment_sheet.json +++ /dev/null @@ -1,57 +0,0 @@ -{ - "actions": [], - "creation": "2020-04-19 23:07:02.220244", - "doctype": "DocType", - "editable_grid": 1, - "engine": "InnoDB", - "field_order": [ - "parameter", - "score", - "time", - "column_break_4", - "comments" - ], - "fields": [ - { - "fieldname": "parameter", - "fieldtype": "Link", - "in_list_view": 1, - "label": "Parameter", - "options": "Patient Assessment Parameter", - "reqd": 1 - }, - { - "fieldname": "score", - "fieldtype": "Select", - "in_list_view": 1, - "label": "Score", - "reqd": 1 - }, - { - "fieldname": "time", - "fieldtype": "Time", - "label": "Time" - }, - { - "fieldname": "column_break_4", - "fieldtype": "Column Break" - }, - { - "fieldname": "comments", - "fieldtype": "Small Text", - "label": "Comments" - } - ], - "istable": 1, - "links": [], - "modified": "2020-04-20 09:56:28.746619", - "modified_by": "Administrator", - "module": "Healthcare", - "name": "Patient Assessment Sheet", - "owner": "Administrator", - "permissions": [], - "quick_entry": 1, - "sort_field": "modified", - "sort_order": "DESC", - "track_changes": 1 -} \ No newline at end of file diff --git a/erpnext/healthcare/doctype/patient_assessment_sheet/patient_assessment_sheet.py b/erpnext/healthcare/doctype/patient_assessment_sheet/patient_assessment_sheet.py deleted file mode 100644 index 4686e9e2617..00000000000 --- a/erpnext/healthcare/doctype/patient_assessment_sheet/patient_assessment_sheet.py +++ /dev/null @@ -1,12 +0,0 @@ -# -*- coding: utf-8 -*- -# Copyright (c) 2020, Frappe Technologies Pvt. Ltd. and contributors -# For license information, please see license.txt - -from __future__ import unicode_literals - -# import frappe -from frappe.model.document import Document - - -class PatientAssessmentSheet(Document): - pass diff --git a/erpnext/healthcare/doctype/patient_assessment_template/__init__.py b/erpnext/healthcare/doctype/patient_assessment_template/__init__.py deleted file mode 100644 index e69de29bb2d..00000000000 diff --git a/erpnext/healthcare/doctype/patient_assessment_template/patient_assessment_template.js b/erpnext/healthcare/doctype/patient_assessment_template/patient_assessment_template.js deleted file mode 100644 index 40419362a4a..00000000000 --- a/erpnext/healthcare/doctype/patient_assessment_template/patient_assessment_template.js +++ /dev/null @@ -1,8 +0,0 @@ -// Copyright (c) 2020, Frappe Technologies Pvt. Ltd. and contributors -// For license information, please see license.txt - -frappe.ui.form.on('Patient Assessment Template', { - // refresh: function(frm) { - - // } -}); diff --git a/erpnext/healthcare/doctype/patient_assessment_template/patient_assessment_template.json b/erpnext/healthcare/doctype/patient_assessment_template/patient_assessment_template.json deleted file mode 100644 index de006b18056..00000000000 --- a/erpnext/healthcare/doctype/patient_assessment_template/patient_assessment_template.json +++ /dev/null @@ -1,109 +0,0 @@ -{ - "actions": [], - "autoname": "field:assessment_name", - "creation": "2020-04-19 19:33:13.204707", - "doctype": "DocType", - "editable_grid": 1, - "engine": "InnoDB", - "field_order": [ - "assessment_name", - "section_break_2", - "parameters", - "assessment_scale_details_section", - "scale_min", - "scale_max", - "column_break_8", - "assessment_description" - ], - "fields": [ - { - "fieldname": "parameters", - "fieldtype": "Table", - "label": "Parameters", - "options": "Patient Assessment Detail" - }, - { - "fieldname": "assessment_name", - "fieldtype": "Data", - "in_list_view": 1, - "label": "Assessment Name", - "reqd": 1, - "unique": 1 - }, - { - "fieldname": "section_break_2", - "fieldtype": "Section Break", - "label": "Assessment Parameters" - }, - { - "fieldname": "assessment_scale_details_section", - "fieldtype": "Section Break", - "label": "Assessment Scale" - }, - { - "fieldname": "scale_min", - "fieldtype": "Int", - "label": "Scale Minimum" - }, - { - "fieldname": "scale_max", - "fieldtype": "Int", - "label": "Scale Maximum" - }, - { - "fieldname": "column_break_8", - "fieldtype": "Column Break" - }, - { - "fieldname": "assessment_description", - "fieldtype": "Small Text", - "label": "Assessment Description" - } - ], - "links": [], - "modified": "2020-04-21 13:14:19.075167", - "modified_by": "Administrator", - "module": "Healthcare", - "name": "Patient Assessment Template", - "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": "Healthcare Administrator", - "share": 1, - "write": 1 - }, - { - "create": 1, - "email": 1, - "export": 1, - "print": 1, - "read": 1, - "report": 1, - "role": "Physician", - "share": 1, - "write": 1 - } - ], - "sort_field": "modified", - "sort_order": "DESC", - "track_changes": 1 -} \ No newline at end of file diff --git a/erpnext/healthcare/doctype/patient_assessment_template/patient_assessment_template.py b/erpnext/healthcare/doctype/patient_assessment_template/patient_assessment_template.py deleted file mode 100644 index e0d8fca37f7..00000000000 --- a/erpnext/healthcare/doctype/patient_assessment_template/patient_assessment_template.py +++ /dev/null @@ -1,12 +0,0 @@ -# -*- coding: utf-8 -*- -# Copyright (c) 2020, Frappe Technologies Pvt. Ltd. and contributors -# For license information, please see license.txt - -from __future__ import unicode_literals - -# import frappe -from frappe.model.document import Document - - -class PatientAssessmentTemplate(Document): - pass diff --git a/erpnext/healthcare/doctype/patient_assessment_template/test_patient_assessment_template.py b/erpnext/healthcare/doctype/patient_assessment_template/test_patient_assessment_template.py deleted file mode 100644 index 7d639cb6af4..00000000000 --- a/erpnext/healthcare/doctype/patient_assessment_template/test_patient_assessment_template.py +++ /dev/null @@ -1,11 +0,0 @@ -# -*- coding: utf-8 -*- -# Copyright (c) 2020, Frappe Technologies Pvt. Ltd. and Contributors -# See license.txt -from __future__ import unicode_literals - -# import frappe -import unittest - - -class TestPatientAssessmentTemplate(unittest.TestCase): - pass diff --git a/erpnext/healthcare/doctype/patient_encounter/__init__.py b/erpnext/healthcare/doctype/patient_encounter/__init__.py deleted file mode 100644 index e69de29bb2d..00000000000 diff --git a/erpnext/healthcare/doctype/patient_encounter/patient_encounter.js b/erpnext/healthcare/doctype/patient_encounter/patient_encounter.js deleted file mode 100644 index c3466260d2b..00000000000 --- a/erpnext/healthcare/doctype/patient_encounter/patient_encounter.js +++ /dev/null @@ -1,397 +0,0 @@ -// Copyright (c) 2016, ESS LLP and contributors -// For license information, please see license.txt - -frappe.ui.form.on('Patient Encounter', { - setup: function(frm) { - frm.get_field('therapies').grid.editable_fields = [ - {fieldname: 'therapy_type', columns: 8}, - {fieldname: 'no_of_sessions', columns: 2} - ]; - frm.get_field('drug_prescription').grid.editable_fields = [ - {fieldname: 'drug_code', columns: 2}, - {fieldname: 'drug_name', columns: 2}, - {fieldname: 'dosage', columns: 2}, - {fieldname: 'period', columns: 2} - ]; - frm.get_field('lab_test_prescription').grid.editable_fields = [ - {fieldname: 'lab_test_code', columns: 2}, - {fieldname: 'lab_test_name', columns: 4}, - {fieldname: 'lab_test_comment', columns: 4} - ]; - }, - - refresh: function(frm) { - refresh_field('drug_prescription'); - refresh_field('lab_test_prescription'); - - if (!frm.doc.__islocal) { - if (frm.doc.docstatus === 1) { - if (frm.doc.inpatient_status == 'Admission Scheduled' || frm.doc.inpatient_status == 'Admitted') { - frm.add_custom_button(__('Schedule Discharge'), function() { - schedule_discharge(frm); - }); - } else if (frm.doc.inpatient_status != 'Discharge Scheduled') { - frm.add_custom_button(__('Schedule Admission'), function() { - schedule_inpatient(frm); - }); - } - } - - frm.add_custom_button(__('Patient History'), function() { - if (frm.doc.patient) { - frappe.route_options = {'patient': frm.doc.patient}; - frappe.set_route('patient_history'); - } else { - frappe.msgprint(__('Please select Patient')); - } - },'View'); - - frm.add_custom_button(__('Vital Signs'), function() { - create_vital_signs(frm); - },'Create'); - - frm.add_custom_button(__('Medical Record'), function() { - create_medical_record(frm); - },'Create'); - - frm.add_custom_button(__('Clinical Procedure'), function() { - create_procedure(frm); - },'Create'); - - if (frm.doc.drug_prescription && frm.doc.inpatient_record && frm.doc.inpatient_status === "Admitted") { - frm.add_custom_button(__('Inpatient Medication Order'), function() { - frappe.model.open_mapped_doc({ - method: 'erpnext.healthcare.doctype.patient_encounter.patient_encounter.make_ip_medication_order', - frm: frm - }); - }, 'Create'); - } - } - - frm.set_query('patient', function() { - return { - filters: {'status': 'Active'} - }; - }); - - frm.set_query('drug_code', 'drug_prescription', function() { - return { - filters: { - is_stock_item: 1 - } - }; - }); - - frm.set_query('lab_test_code', 'lab_test_prescription', function() { - return { - filters: { - is_billable: 1 - } - }; - }); - - frm.set_query('appointment', function() { - return { - filters: { - // Scheduled filter for demo ... - status:['in',['Open','Scheduled']] - } - }; - }); - - frm.set_df_property('patient', 'read_only', frm.doc.appointment ? 1 : 0); - }, - - appointment: function(frm) { - frm.events.set_appointment_fields(frm); - }, - - patient: function(frm) { - frm.events.set_patient_info(frm); - }, - - practitioner: function(frm) { - if (!frm.doc.practitioner) { - frm.set_value('practitioner_name', ''); - } - }, - set_appointment_fields: function(frm) { - if (frm.doc.appointment) { - frappe.call({ - method: 'frappe.client.get', - args: { - doctype: 'Patient Appointment', - name: frm.doc.appointment - }, - callback: function(data) { - let values = { - 'patient':data.message.patient, - 'type': data.message.appointment_type, - 'practitioner': data.message.practitioner, - 'invoiced': data.message.invoiced, - 'company': data.message.company - }; - frm.set_value(values); - frm.set_df_property('patient', 'read_only', 1); - } - }); - } - else { - let values = { - 'patient': '', - 'patient_name': '', - 'type': '', - 'practitioner': '', - 'invoiced': 0, - 'patient_sex': '', - 'patient_age': '', - 'inpatient_record': '', - 'inpatient_status': '' - }; - frm.set_value(values); - frm.set_df_property('patient', 'read_only', 0); - } - }, - - set_patient_info: function(frm) { - if (frm.doc.patient) { - frappe.call({ - method: 'erpnext.healthcare.doctype.patient.patient.get_patient_detail', - args: { - patient: frm.doc.patient - }, - callback: function(data) { - let age = ''; - if (data.message.dob) { - age = calculate_age(data.message.dob); - } - let values = { - 'patient_age': age, - 'patient_name':data.message.patient_name, - 'patient_sex': data.message.sex, - 'inpatient_record': data.message.inpatient_record, - 'inpatient_status': data.message.inpatient_status - }; - frm.set_value(values); - } - }); - } else { - let values = { - 'patient_age': '', - 'patient_name':'', - 'patient_sex': '', - 'inpatient_record': '', - 'inpatient_status': '' - }; - frm.set_value(values); - } - }, - - get_applicable_treatment_plans: function(frm) { - frappe.call({ - method: 'get_applicable_treatment_plans', - doc: frm.doc, - args: {'encounter': frm.doc}, - freeze: true, - freeze_message: __('Fetching Treatment Plans'), - callback: function() { - new frappe.ui.form.MultiSelectDialog({ - doctype: "Treatment Plan Template", - target: this.cur_frm, - setters: { - medical_department: "", - }, - action(selections) { - frappe.call({ - method: 'set_treatment_plans', - doc: frm.doc, - args: selections, - }).then(() => { - frm.refresh_field('drug_prescription'); - frm.refresh_field('procedure_prescription'); - frm.refresh_field('lab_test_prescription'); - frm.refresh_field('therapies'); - }); - cur_dialog.hide(); - } - }); - - - } - }); - }, - -}); - -var schedule_inpatient = function(frm) { - var dialog = new frappe.ui.Dialog({ - title: 'Patient Admission', - fields: [ - {fieldtype: 'Link', label: 'Medical Department', fieldname: 'medical_department', options: 'Medical Department', reqd: 1}, - {fieldtype: 'Link', label: 'Healthcare Practitioner (Primary)', fieldname: 'primary_practitioner', options: 'Healthcare Practitioner', reqd: 1}, - {fieldtype: 'Link', label: 'Healthcare Practitioner (Secondary)', fieldname: 'secondary_practitioner', options: 'Healthcare Practitioner'}, - {fieldtype: 'Column Break'}, - {fieldtype: 'Date', label: 'Admission Ordered For', fieldname: 'admission_ordered_for', default: 'Today'}, - {fieldtype: 'Link', label: 'Service Unit Type', fieldname: 'service_unit_type', options: 'Healthcare Service Unit Type'}, - {fieldtype: 'Int', label: 'Expected Length of Stay', fieldname: 'expected_length_of_stay'}, - {fieldtype: 'Section Break'}, - {fieldtype: 'Long Text', label: 'Admission Instructions', fieldname: 'admission_instruction'} - ], - primary_action_label: __('Order Admission'), - primary_action : function() { - var args = { - patient: frm.doc.patient, - admission_encounter: frm.doc.name, - referring_practitioner: frm.doc.practitioner, - company: frm.doc.company, - medical_department: dialog.get_value('medical_department'), - primary_practitioner: dialog.get_value('primary_practitioner'), - secondary_practitioner: dialog.get_value('secondary_practitioner'), - admission_ordered_for: dialog.get_value('admission_ordered_for'), - admission_service_unit_type: dialog.get_value('service_unit_type'), - expected_length_of_stay: dialog.get_value('expected_length_of_stay'), - admission_instruction: dialog.get_value('admission_instruction') - } - frappe.call({ - method: 'erpnext.healthcare.doctype.inpatient_record.inpatient_record.schedule_inpatient', - args: { - args: args - }, - callback: function(data) { - if (!data.exc) { - frm.reload_doc(); - } - }, - freeze: true, - freeze_message: __('Scheduling Patient Admission') - }); - frm.refresh_fields(); - dialog.hide(); - } - }); - - dialog.set_values({ - 'medical_department': frm.doc.medical_department, - 'primary_practitioner': frm.doc.practitioner, - }); - - dialog.fields_dict['service_unit_type'].get_query = function() { - return { - filters: { - 'inpatient_occupancy': 1, - 'allow_appointments': 0 - } - }; - }; - - dialog.show(); - dialog.$wrapper.find('.modal-dialog').css('width', '800px'); -}; - -var schedule_discharge = function(frm) { - var dialog = new frappe.ui.Dialog ({ - title: 'Inpatient Discharge', - fields: [ - {fieldtype: 'Date', label: 'Discharge Ordered Date', fieldname: 'discharge_ordered_date', default: 'Today', read_only: 1}, - {fieldtype: 'Date', label: 'Followup Date', fieldname: 'followup_date'}, - {fieldtype: 'Column Break'}, - {fieldtype: 'Small Text', label: 'Discharge Instructions', fieldname: 'discharge_instructions'}, - {fieldtype: 'Section Break', label:'Discharge Summary'}, - {fieldtype: 'Long Text', label: 'Discharge Note', fieldname: 'discharge_note'} - ], - primary_action_label: __('Order Discharge'), - primary_action : function() { - var args = { - patient: frm.doc.patient, - discharge_encounter: frm.doc.name, - discharge_practitioner: frm.doc.practitioner, - discharge_ordered_date: dialog.get_value('discharge_ordered_date'), - followup_date: dialog.get_value('followup_date'), - discharge_instructions: dialog.get_value('discharge_instructions'), - discharge_note: dialog.get_value('discharge_note') - } - frappe.call ({ - method: 'erpnext.healthcare.doctype.inpatient_record.inpatient_record.schedule_discharge', - args: {args}, - callback: function(data) { - if(!data.exc){ - frm.reload_doc(); - } - }, - freeze: true, - freeze_message: 'Scheduling Inpatient Discharge' - }); - frm.refresh_fields(); - dialog.hide(); - } - }); - - dialog.show(); - dialog.$wrapper.find('.modal-dialog').css('width', '800px'); -}; - -let create_medical_record = function(frm) { - if (!frm.doc.patient) { - frappe.throw(__('Please select patient')); - } - frappe.route_options = { - 'patient': frm.doc.patient, - 'status': 'Open', - 'reference_doctype': 'Patient Medical Record', - 'reference_owner': frm.doc.owner - }; - frappe.new_doc('Patient Medical Record'); -}; - -let create_vital_signs = function(frm) { - if (!frm.doc.patient) { - frappe.throw(__('Please select patient')); - } - frappe.route_options = { - 'patient': frm.doc.patient, - 'encounter': frm.doc.name, - 'company': frm.doc.company - }; - frappe.new_doc('Vital Signs'); -}; - -let create_procedure = function(frm) { - if (!frm.doc.patient) { - frappe.throw(__('Please select patient')); - } - frappe.route_options = { - 'patient': frm.doc.patient, - 'medical_department': frm.doc.medical_department, - 'company': frm.doc.company - }; - frappe.new_doc('Clinical Procedure'); -}; - -frappe.ui.form.on('Drug Prescription', { - dosage: function(frm, cdt, cdn){ - frappe.model.set_value(cdt, cdn, 'update_schedule', 1); - let child = locals[cdt][cdn]; - if (child.dosage) { - frappe.model.set_value(cdt, cdn, 'interval_uom', 'Day'); - frappe.model.set_value(cdt, cdn, 'interval', 1); - } - }, - period: function(frm, cdt, cdn) { - frappe.model.set_value(cdt, cdn, 'update_schedule', 1); - }, - interval_uom: function(frm, cdt, cdn) { - frappe.model.set_value(cdt, cdn, 'update_schedule', 1); - let child = locals[cdt][cdn]; - if (child.interval_uom == 'Hour') { - frappe.model.set_value(cdt, cdn, 'dosage', null); - } - } -}); - -let calculate_age = function(birth) { - let ageMS = Date.parse(Date()) - Date.parse(birth); - let age = new Date(); - age.setTime(ageMS); - let years = age.getFullYear() - 1970; - return `${years} ${__('Years(s)')} ${age.getMonth()} ${__('Month(s)')} ${age.getDate()} ${__('Day(s)')}`; -}; diff --git a/erpnext/healthcare/doctype/patient_encounter/patient_encounter.json b/erpnext/healthcare/doctype/patient_encounter/patient_encounter.json deleted file mode 100644 index 994597dca7c..00000000000 --- a/erpnext/healthcare/doctype/patient_encounter/patient_encounter.json +++ /dev/null @@ -1,368 +0,0 @@ -{ - "actions": [], - "allow_copy": 1, - "allow_import": 1, - "autoname": "naming_series:", - "beta": 1, - "creation": "2016-04-21 10:53:44.637684", - "doctype": "DocType", - "document_type": "Document", - "editable_grid": 1, - "engine": "InnoDB", - "field_order": [ - "naming_series", - "title", - "appointment", - "appointment_type", - "patient", - "patient_name", - "patient_sex", - "patient_age", - "inpatient_record", - "inpatient_status", - "column_break_6", - "company", - "encounter_date", - "encounter_time", - "practitioner", - "practitioner_name", - "medical_department", - "invoiced", - "sb_symptoms", - "symptoms", - "symptoms_in_print", - "get_applicable_treatment_plans", - "physical_examination", - "diagnosis", - "diagnosis_in_print", - "codification", - "codification_table", - "sb_drug_prescription", - "drug_prescription", - "sb_test_prescription", - "lab_test_prescription", - "sb_procedures", - "procedure_prescription", - "rehabilitation_section", - "therapy_plan", - "therapies", - "section_break_33", - "encounter_comment", - "sb_refs", - "amended_from" - ], - "fields": [ - { - "allow_on_submit": 1, - "fieldname": "inpatient_record", - "fieldtype": "Link", - "label": "Inpatient Record", - "options": "Inpatient Record", - "read_only": 1 - }, - { - "fieldname": "naming_series", - "fieldtype": "Select", - "label": "Series", - "no_copy": 1, - "options": "HLC-ENC-.YYYY.-", - "set_only_once": 1 - }, - { - "fieldname": "appointment", - "fieldtype": "Link", - "ignore_user_permissions": 1, - "label": "Appointment", - "options": "Patient Appointment", - "search_index": 1, - "set_only_once": 1 - }, - { - "fieldname": "patient", - "fieldtype": "Link", - "ignore_user_permissions": 1, - "in_standard_filter": 1, - "label": "Patient", - "options": "Patient", - "reqd": 1, - "search_index": 1 - }, - { - "fieldname": "patient_name", - "fieldtype": "Data", - "label": "Patient Name", - "read_only": 1 - }, - { - "fieldname": "patient_age", - "fieldtype": "Data", - "label": "Age", - "read_only": 1 - }, - { - "fieldname": "patient_sex", - "fieldtype": "Link", - "label": "Gender", - "options": "Gender", - "read_only": 1 - }, - { - "fieldname": "company", - "fieldtype": "Link", - "label": "Company", - "options": "Company" - }, - { - "fieldname": "column_break_6", - "fieldtype": "Column Break" - }, - { - "fieldname": "practitioner", - "fieldtype": "Link", - "in_standard_filter": 1, - "label": "Healthcare Practitioner", - "options": "Healthcare Practitioner", - "reqd": 1 - }, - { - "default": "Today", - "fieldname": "encounter_date", - "fieldtype": "Date", - "in_list_view": 1, - "label": "Encounter Date", - "reqd": 1 - }, - { - "fieldname": "encounter_time", - "fieldtype": "Time", - "label": "Encounter Time", - "reqd": 1 - }, - { - "default": "0", - "fieldname": "invoiced", - "fieldtype": "Check", - "label": "Invoiced", - "no_copy": 1, - "read_only": 1 - }, - { - "fieldname": "sb_symptoms", - "fieldtype": "Section Break", - "label": "Encounter Impression" - }, - { - "fieldname": "symptoms", - "fieldtype": "Table MultiSelect", - "ignore_xss_filter": 1, - "label": "Symptoms", - "no_copy": 1, - "options": "Patient Encounter Symptom" - }, - { - "default": "0", - "depends_on": "eval: doc.symptoms != ''", - "fieldname": "symptoms_in_print", - "fieldtype": "Check", - "label": "In print", - "no_copy": 1, - "print_hide": 1, - "report_hide": 1 - }, - { - "fieldname": "physical_examination", - "fieldtype": "Column Break" - }, - { - "fieldname": "diagnosis", - "fieldtype": "Table MultiSelect", - "ignore_xss_filter": 1, - "label": "Diagnosis", - "no_copy": 1, - "options": "Patient Encounter Diagnosis" - }, - { - "default": "1", - "depends_on": "eval: doc.diagnosis != ''", - "fieldname": "diagnosis_in_print", - "fieldtype": "Check", - "label": "In print", - "no_copy": 1, - "print_hide": 1, - "report_hide": 1 - }, - { - "collapsible": 1, - "fieldname": "codification", - "fieldtype": "Section Break", - "label": "Medical Coding" - }, - { - "fieldname": "codification_table", - "fieldtype": "Table", - "label": "Medical Codes", - "options": "Codification Table" - }, - { - "fieldname": "sb_drug_prescription", - "fieldtype": "Section Break", - "label": "Medications" - }, - { - "fieldname": "drug_prescription", - "fieldtype": "Table", - "label": "Drug Prescription", - "options": "Drug Prescription" - }, - { - "fieldname": "sb_test_prescription", - "fieldtype": "Section Break", - "label": "Investigations" - }, - { - "fieldname": "lab_test_prescription", - "fieldtype": "Table", - "label": "Lab Tests", - "options": "Lab Prescription" - }, - { - "fieldname": "sb_procedures", - "fieldtype": "Section Break", - "label": "Procedures" - }, - { - "fieldname": "procedure_prescription", - "fieldtype": "Table", - "label": "Clinical Procedures", - "no_copy": 1, - "options": "Procedure Prescription" - }, - { - "fieldname": "encounter_comment", - "fieldtype": "Small Text", - "ignore_xss_filter": 1, - "label": "Review Details", - "no_copy": 1 - }, - { - "fieldname": "amended_from", - "fieldtype": "Link", - "label": "Amended From", - "no_copy": 1, - "options": "Patient Encounter", - "print_hide": 1, - "read_only": 1 - }, - { - "fieldname": "rehabilitation_section", - "fieldtype": "Section Break", - "label": "Rehabilitation" - }, - { - "fieldname": "therapies", - "fieldtype": "Table", - "label": "Therapies", - "options": "Therapy Plan Detail" - }, - { - "fieldname": "section_break_33", - "fieldtype": "Section Break" - }, - { - "fieldname": "therapy_plan", - "fieldtype": "Link", - "hidden": 1, - "label": "Therapy Plan", - "options": "Therapy Plan", - "read_only": 1 - }, - { - "fieldname": "appointment_type", - "fieldtype": "Link", - "ignore_user_permissions": 1, - "label": "Appointment Type", - "no_copy": 1, - "options": "Appointment Type", - "print_hide": 1, - "read_only": 1, - "report_hide": 1 - }, - { - "fetch_from": "practitioner.department", - "fieldname": "medical_department", - "fieldtype": "Link", - "ignore_user_permissions": 1, - "in_standard_filter": 1, - "label": "Department", - "options": "Medical Department", - "read_only": 1 - }, - { - "allow_on_submit": 1, - "fieldname": "inpatient_status", - "fieldtype": "Data", - "label": "Inpatient Status", - "read_only": 1 - }, - { - "fieldname": "sb_refs", - "fieldtype": "Section Break" - }, - { - "fetch_from": "practitioner.practitioner_name", - "fieldname": "practitioner_name", - "fieldtype": "Data", - "in_list_view": 1, - "label": "Practitioner Name", - "read_only": 1 - }, - { - "allow_on_submit": 1, - "fieldname": "title", - "fieldtype": "Data", - "hidden": 1, - "label": "Title", - "no_copy": 1, - "print_hide": 1, - "read_only": 1 - }, - { - "depends_on": "eval:doc.patient", - "fieldname": "get_applicable_treatment_plans", - "fieldtype": "Button", - "label": "Get Applicable Treatment Plans" - } - ], - "is_submittable": 1, - "links": [], - "modified": "2021-07-27 11:39:12.347704", - "modified_by": "Administrator", - "module": "Healthcare", - "name": "Patient Encounter", - "owner": "Administrator", - "permissions": [ - { - "amend": 1, - "cancel": 1, - "create": 1, - "delete": 1, - "email": 1, - "export": 1, - "print": 1, - "read": 1, - "report": 1, - "role": "Physician", - "share": 1, - "submit": 1, - "write": 1 - } - ], - "restrict_to_domain": "Healthcare", - "search_fields": "patient, practitioner, medical_department, encounter_date, encounter_time", - "show_name_in_global_search": 1, - "sort_field": "modified", - "sort_order": "DESC", - "title_field": "title", - "track_changes": 1, - "track_seen": 1 -} diff --git a/erpnext/healthcare/doctype/patient_encounter/patient_encounter.py b/erpnext/healthcare/doctype/patient_encounter/patient_encounter.py deleted file mode 100644 index 2daa6c145c8..00000000000 --- a/erpnext/healthcare/doctype/patient_encounter/patient_encounter.py +++ /dev/null @@ -1,182 +0,0 @@ -# -*- coding: utf-8 -*- -# Copyright (c) 2015, ESS LLP and contributors -# For license information, please see license.txt - -from __future__ import unicode_literals - -import frappe -from frappe import _ -from frappe.model.document import Document -from frappe.model.mapper import get_mapped_doc -from frappe.utils import add_days, getdate - - -class PatientEncounter(Document): - def validate(self): - self.set_title() - - def on_update(self): - if self.appointment: - frappe.db.set_value('Patient Appointment', self.appointment, 'status', 'Closed') - - def on_submit(self): - if self.therapies: - create_therapy_plan(self) - - def on_cancel(self): - if self.appointment: - frappe.db.set_value('Patient Appointment', self.appointment, 'status', 'Open') - - if self.inpatient_record and self.drug_prescription: - delete_ip_medication_order(self) - - def set_title(self): - self.title = _('{0} with {1}').format(self.patient_name or self.patient, - self.practitioner_name or self.practitioner)[:100] - - @frappe.whitelist() - @staticmethod - def get_applicable_treatment_plans(encounter): - patient = frappe.get_doc('Patient', encounter['patient']) - - plan_filters = {} - plan_filters['name'] = ['in', []] - - age = patient.age - if age: - plan_filters['patient_age_from'] = ['<=', age.years] - plan_filters['patient_age_to'] = ['>=', age.years] - - gender = patient.sex - if gender: - plan_filters['gender'] = ['in', [gender, None]] - - diagnosis = encounter.get('diagnosis') - if diagnosis: - diagnosis = [_diagnosis['diagnosis'] for _diagnosis in encounter['diagnosis']] - filters = [ - ['diagnosis', 'in', diagnosis], - ['parenttype', '=', 'Treatment Plan Template'], - ] - diagnosis = frappe.get_list('Patient Encounter Diagnosis', filters=filters, fields='*') - plan_names = [_diagnosis['parent'] for _diagnosis in diagnosis] - plan_filters['name'][1].extend(plan_names) - - symptoms = encounter.get('symptoms') - if symptoms: - symptoms = [symptom['complaint'] for symptom in encounter['symptoms']] - filters = [ - ['complaint', 'in', symptoms], - ['parenttype', '=', 'Treatment Plan Template'], - ] - symptoms = frappe.get_list('Patient Encounter Symptom', filters=filters, fields='*') - plan_names = [symptom['parent'] for symptom in symptoms] - plan_filters['name'][1].extend(plan_names) - - if not plan_filters['name'][1]: - plan_filters.pop('name') - - plans = frappe.get_list('Treatment Plan Template', fields='*', filters=plan_filters) - - return plans - - @frappe.whitelist() - def set_treatment_plans(self, treatment_plans=None): - for treatment_plan in treatment_plans: - self.set_treatment_plan(treatment_plan) - - def set_treatment_plan(self, plan): - plan_items = frappe.get_list('Treatment Plan Template Item', filters={'parent': plan}, fields='*') - for plan_item in plan_items: - self.set_treatment_plan_item(plan_item) - - drugs = frappe.get_list('Drug Prescription', filters={'parent': plan}, fields='*') - for drug in drugs: - self.append('drug_prescription', drug) - - self.save() - - def set_treatment_plan_item(self, plan_item): - if plan_item.type == 'Clinical Procedure Template': - self.append('procedure_prescription', { - 'procedure': plan_item.template - }) - - if plan_item.type == 'Lab Test Template': - self.append('lab_test_prescription', { - 'lab_test_code': plan_item.template - }) - - if plan_item.type == 'Therapy Type': - self.append('therapies', { - 'therapy_type': plan_item.template - }) - - -@frappe.whitelist() -def make_ip_medication_order(source_name, target_doc=None): - def set_missing_values(source, target): - target.start_date = source.encounter_date - for entry in source.drug_prescription: - if entry.drug_code: - dosage = frappe.get_doc('Prescription Dosage', entry.dosage) - dates = get_prescription_dates(entry.period, target.start_date) - for date in dates: - for dose in dosage.dosage_strength: - order = target.append('medication_orders') - order.drug = entry.drug_code - order.drug_name = entry.drug_name - order.dosage = dose.strength - order.instructions = entry.comment - order.dosage_form = entry.dosage_form - order.date = date - order.time = dose.strength_time - target.end_date = dates[-1] - - doc = get_mapped_doc('Patient Encounter', source_name, { - 'Patient Encounter': { - 'doctype': 'Inpatient Medication Order', - 'field_map': { - 'name': 'patient_encounter', - 'patient': 'patient', - 'patient_name': 'patient_name', - 'patient_age': 'patient_age', - 'inpatient_record': 'inpatient_record', - 'practitioner': 'practitioner', - 'start_date': 'encounter_date' - }, - } - }, target_doc, set_missing_values) - - return doc - - -def get_prescription_dates(period, start_date): - prescription_duration = frappe.get_doc('Prescription Duration', period) - days = prescription_duration.get_days() - dates = [start_date] - for i in range(1, days): - dates.append(add_days(getdate(start_date), i)) - return dates - - -def create_therapy_plan(encounter): - if len(encounter.therapies): - doc = frappe.new_doc('Therapy Plan') - doc.patient = encounter.patient - doc.start_date = encounter.encounter_date - for entry in encounter.therapies: - doc.append('therapy_plan_details', { - 'therapy_type': entry.therapy_type, - 'no_of_sessions': entry.no_of_sessions - }) - doc.save(ignore_permissions=True) - if doc.get('name'): - encounter.db_set('therapy_plan', doc.name) - frappe.msgprint(_('Therapy Plan {0} created successfully.').format(frappe.bold(doc.name)), alert=True) - - -def delete_ip_medication_order(encounter): - record = frappe.db.exists('Inpatient Medication Order', {'patient_encounter': encounter.name}) - if record: - frappe.delete_doc('Inpatient Medication Order', record, force=1) diff --git a/erpnext/healthcare/doctype/patient_encounter/patient_encounter_dashboard.py b/erpnext/healthcare/doctype/patient_encounter/patient_encounter_dashboard.py deleted file mode 100644 index 3b64d988715..00000000000 --- a/erpnext/healthcare/doctype/patient_encounter/patient_encounter_dashboard.py +++ /dev/null @@ -1,24 +0,0 @@ -from __future__ import unicode_literals - -from frappe import _ - - -def get_data(): - return { - 'fieldname': 'encounter', - 'non_standard_fieldnames': { - 'Patient Medical Record': 'reference_name', - 'Inpatient Medication Order': 'patient_encounter' - }, - 'transactions': [ - { - 'label': _('Records'), - 'items': ['Vital Signs', 'Patient Medical Record'] - }, - { - 'label': _('Orders'), - 'items': ['Inpatient Medication Order'] - } - ], - 'disable_create_buttons': ['Inpatient Medication Order'] - } diff --git a/erpnext/healthcare/doctype/patient_encounter/patient_encounter_list.js b/erpnext/healthcare/doctype/patient_encounter/patient_encounter_list.js deleted file mode 100644 index d8f63bd0fa5..00000000000 --- a/erpnext/healthcare/doctype/patient_encounter/patient_encounter_list.js +++ /dev/null @@ -1,6 +0,0 @@ -/* -(c) ESS 2015-16 -*/ -frappe.listview_settings['Patient Encounter'] = { - filters:[["docstatus","!=","2"]] -}; diff --git a/erpnext/healthcare/doctype/patient_encounter/test_patient_encounter.py b/erpnext/healthcare/doctype/patient_encounter/test_patient_encounter.py deleted file mode 100644 index fa643a31d8e..00000000000 --- a/erpnext/healthcare/doctype/patient_encounter/test_patient_encounter.py +++ /dev/null @@ -1,87 +0,0 @@ -# -*- coding: utf-8 -*- -# Copyright (c) 2018, Frappe Technologies Pvt. Ltd. and Contributors -# See license.txt -from __future__ import unicode_literals - -import unittest - -import frappe - -from erpnext.healthcare.doctype.patient_encounter.patient_encounter import PatientEncounter - - -class TestPatientEncounter(unittest.TestCase): - def setUp(self): - try: - gender_m = frappe.get_doc({ - 'doctype': 'Gender', - 'gender': 'MALE' - }).insert() - gender_f = frappe.get_doc({ - 'doctype': 'Gender', - 'gender': 'FEMALE' - }).insert() - except frappe.exceptions.DuplicateEntryError: - gender_m = frappe.get_doc({ - 'doctype': 'Gender', - 'gender': 'MALE' - }) - gender_f = frappe.get_doc({ - 'doctype': 'Gender', - 'gender': 'FEMALE' - }) - - self.patient_male = frappe.get_doc({ - 'doctype': 'Patient', - 'first_name': 'John', - 'sex': gender_m.gender, - }).insert() - self.patient_female = frappe.get_doc({ - 'doctype': 'Patient', - 'first_name': 'Curie', - 'sex': gender_f.gender, - }).insert() - self.practitioner = frappe.get_doc({ - 'doctype': 'Healthcare Practitioner', - 'first_name': 'Doc', - 'sex': 'MALE', - }).insert() - try: - self.care_plan_male = frappe.get_doc({ - 'doctype': 'Treatment Plan Template', - 'template_name': 'test plan - m', - 'gender': gender_m.gender, - }).insert() - self.care_plan_female = frappe.get_doc({ - 'doctype': 'Treatment Plan Template', - 'template_name': 'test plan - f', - 'gender': gender_f.gender, - }).insert() - except frappe.exceptions.DuplicateEntryError: - self.care_plan_male = frappe.get_doc({ - 'doctype': 'Treatment Plan Template', - 'template_name': 'test plan - m', - 'gender': gender_m.gender, - }) - self.care_plan_female = frappe.get_doc({ - 'doctype': 'Treatment Plan Template', - 'template_name': 'test plan - f', - 'gender': gender_f.gender, - }) - - def test_treatment_plan_template_filter(self): - encounter = frappe.get_doc({ - 'doctype': 'Patient Encounter', - 'patient': self.patient_male.name, - 'practitioner': self.practitioner.name, - }).insert() - plans = PatientEncounter.get_applicable_treatment_plans(encounter.as_dict()) - self.assertEqual(plans[0]['name'], self.care_plan_male.template_name) - - encounter = frappe.get_doc({ - 'doctype': 'Patient Encounter', - 'patient': self.patient_female.name, - 'practitioner': self.practitioner.name, - }).insert() - plans = PatientEncounter.get_applicable_treatment_plans(encounter.as_dict()) - self.assertEqual(plans[0]['name'], self.care_plan_female.template_name) diff --git a/erpnext/healthcare/doctype/patient_encounter_diagnosis/__init__.py b/erpnext/healthcare/doctype/patient_encounter_diagnosis/__init__.py deleted file mode 100644 index e69de29bb2d..00000000000 diff --git a/erpnext/healthcare/doctype/patient_encounter_diagnosis/patient_encounter_diagnosis.json b/erpnext/healthcare/doctype/patient_encounter_diagnosis/patient_encounter_diagnosis.json deleted file mode 100644 index 00ca309d63e..00000000000 --- a/erpnext/healthcare/doctype/patient_encounter_diagnosis/patient_encounter_diagnosis.json +++ /dev/null @@ -1,33 +0,0 @@ -{ - "actions": [], - "beta": 1, - "creation": "2020-02-26 16:48:16.835105", - "doctype": "DocType", - "editable_grid": 1, - "engine": "InnoDB", - "field_order": [ - "diagnosis" - ], - "fields": [ - { - "fieldname": "diagnosis", - "fieldtype": "Link", - "in_list_view": 1, - "label": "Diagnosis", - "options": "Diagnosis", - "reqd": 1 - } - ], - "istable": 1, - "links": [], - "modified": "2020-02-26 16:58:16.480583", - "modified_by": "Administrator", - "module": "Healthcare", - "name": "Patient Encounter Diagnosis", - "owner": "Administrator", - "permissions": [], - "quick_entry": 1, - "sort_field": "modified", - "sort_order": "DESC", - "track_changes": 1 -} \ No newline at end of file diff --git a/erpnext/healthcare/doctype/patient_encounter_diagnosis/patient_encounter_diagnosis.py b/erpnext/healthcare/doctype/patient_encounter_diagnosis/patient_encounter_diagnosis.py deleted file mode 100644 index e4d2069a50e..00000000000 --- a/erpnext/healthcare/doctype/patient_encounter_diagnosis/patient_encounter_diagnosis.py +++ /dev/null @@ -1,12 +0,0 @@ -# -*- coding: utf-8 -*- -# Copyright (c) 2020, Frappe Technologies Pvt. Ltd. and contributors -# For license information, please see license.txt - -from __future__ import unicode_literals - -# import frappe -from frappe.model.document import Document - - -class PatientEncounterDiagnosis(Document): - pass diff --git a/erpnext/healthcare/doctype/patient_encounter_symptom/__init__.py b/erpnext/healthcare/doctype/patient_encounter_symptom/__init__.py deleted file mode 100644 index e69de29bb2d..00000000000 diff --git a/erpnext/healthcare/doctype/patient_encounter_symptom/patient_encounter_symptom.json b/erpnext/healthcare/doctype/patient_encounter_symptom/patient_encounter_symptom.json deleted file mode 100644 index bc921458674..00000000000 --- a/erpnext/healthcare/doctype/patient_encounter_symptom/patient_encounter_symptom.json +++ /dev/null @@ -1,33 +0,0 @@ -{ - "actions": [], - "beta": 1, - "creation": "2020-02-26 16:47:00.525657", - "doctype": "DocType", - "editable_grid": 1, - "engine": "InnoDB", - "field_order": [ - "complaint" - ], - "fields": [ - { - "fieldname": "complaint", - "fieldtype": "Link", - "in_list_view": 1, - "label": "Complaint", - "options": "Complaint", - "reqd": 1 - } - ], - "istable": 1, - "links": [], - "modified": "2020-02-26 16:57:37.997481", - "modified_by": "Administrator", - "module": "Healthcare", - "name": "Patient Encounter Symptom", - "owner": "Administrator", - "permissions": [], - "quick_entry": 1, - "sort_field": "modified", - "sort_order": "DESC", - "track_changes": 1 -} \ No newline at end of file diff --git a/erpnext/healthcare/doctype/patient_encounter_symptom/patient_encounter_symptom.py b/erpnext/healthcare/doctype/patient_encounter_symptom/patient_encounter_symptom.py deleted file mode 100644 index 47f2a2be7e9..00000000000 --- a/erpnext/healthcare/doctype/patient_encounter_symptom/patient_encounter_symptom.py +++ /dev/null @@ -1,12 +0,0 @@ -# -*- coding: utf-8 -*- -# Copyright (c) 2020, Frappe Technologies Pvt. Ltd. and contributors -# For license information, please see license.txt - -from __future__ import unicode_literals - -# import frappe -from frappe.model.document import Document - - -class PatientEncounterSymptom(Document): - pass diff --git a/erpnext/healthcare/doctype/patient_history_custom_document_type/__init__.py b/erpnext/healthcare/doctype/patient_history_custom_document_type/__init__.py deleted file mode 100644 index e69de29bb2d..00000000000 diff --git a/erpnext/healthcare/doctype/patient_history_custom_document_type/patient_history_custom_document_type.json b/erpnext/healthcare/doctype/patient_history_custom_document_type/patient_history_custom_document_type.json deleted file mode 100644 index 3025c7b06d7..00000000000 --- a/erpnext/healthcare/doctype/patient_history_custom_document_type/patient_history_custom_document_type.json +++ /dev/null @@ -1,55 +0,0 @@ -{ - "actions": [], - "creation": "2020-11-25 13:40:23.054469", - "doctype": "DocType", - "editable_grid": 1, - "engine": "InnoDB", - "field_order": [ - "document_type", - "date_fieldname", - "add_edit_fields", - "selected_fields" - ], - "fields": [ - { - "fieldname": "document_type", - "fieldtype": "Link", - "in_list_view": 1, - "label": "Document Type", - "options": "DocType", - "reqd": 1 - }, - { - "fieldname": "selected_fields", - "fieldtype": "Code", - "label": "Selected Fields", - "read_only": 1 - }, - { - "fieldname": "add_edit_fields", - "fieldtype": "Button", - "in_list_view": 1, - "label": "Add / Edit Fields" - }, - { - "fieldname": "date_fieldname", - "fieldtype": "Data", - "in_list_view": 1, - "label": "Date Fieldname", - "reqd": 1 - } - ], - "index_web_pages_for_search": 1, - "istable": 1, - "links": [], - "modified": "2020-11-30 13:54:37.474671", - "modified_by": "Administrator", - "module": "Healthcare", - "name": "Patient History Custom Document Type", - "owner": "Administrator", - "permissions": [], - "quick_entry": 1, - "sort_field": "modified", - "sort_order": "DESC", - "track_changes": 1 -} \ No newline at end of file diff --git a/erpnext/healthcare/doctype/patient_history_custom_document_type/patient_history_custom_document_type.py b/erpnext/healthcare/doctype/patient_history_custom_document_type/patient_history_custom_document_type.py deleted file mode 100644 index 34e15dc46a2..00000000000 --- a/erpnext/healthcare/doctype/patient_history_custom_document_type/patient_history_custom_document_type.py +++ /dev/null @@ -1,12 +0,0 @@ -# -*- coding: utf-8 -*- -# Copyright (c) 2020, Frappe Technologies Pvt. Ltd. and contributors -# For license information, please see license.txt - -from __future__ import unicode_literals - -# import frappe -from frappe.model.document import Document - - -class PatientHistoryCustomDocumentType(Document): - pass diff --git a/erpnext/healthcare/doctype/patient_history_settings/__init__.py b/erpnext/healthcare/doctype/patient_history_settings/__init__.py deleted file mode 100644 index e69de29bb2d..00000000000 diff --git a/erpnext/healthcare/doctype/patient_history_settings/patient_history_settings.js b/erpnext/healthcare/doctype/patient_history_settings/patient_history_settings.js deleted file mode 100644 index 453da6a12bf..00000000000 --- a/erpnext/healthcare/doctype/patient_history_settings/patient_history_settings.js +++ /dev/null @@ -1,133 +0,0 @@ -// Copyright (c) 2020, Frappe Technologies Pvt. Ltd. and contributors -// For license information, please see license.txt - -frappe.ui.form.on('Patient History Settings', { - refresh: function(frm) { - frm.set_query('document_type', 'custom_doctypes', () => { - return { - filters: { - custom: 1, - is_submittable: 1, - module: 'Healthcare', - } - }; - }); - }, - - field_selector: function(frm, doc, standard=1) { - let document_fields = []; - if (doc.selected_fields) - document_fields = (JSON.parse(doc.selected_fields)).map(f => f.fieldname); - - frm.call({ - method: 'get_doctype_fields', - doc: frm.doc, - args: { - document_type: doc.document_type, - fields: document_fields - }, - freeze: true, - callback: function(r) { - if (r.message) { - let doctype = 'Patient History Custom Document Type'; - if (standard) - doctype = 'Patient History Standard Document Type'; - - frm.events.show_field_selector_dialog(frm, doc, doctype, r.message); - } - } - }); - }, - - show_field_selector_dialog: function(frm, doc, doctype, doc_fields) { - let d = new frappe.ui.Dialog({ - title: __('{0} Fields', [__(doc.document_type)]), - fields: [ - { - label: __('Select Fields'), - fieldtype: 'MultiCheck', - fieldname: 'fields', - options: doc_fields, - columns: 2 - } - ] - }); - - d.$body.prepend(` - ` - ); - - frappe.utils.setup_search(d.$body, '.unit-checkbox', '.label-area'); - - d.set_primary_action(__('Save'), () => { - let values = d.get_values().fields; - - let selected_fields = []; - - frappe.model.with_doctype(doc.document_type, function() { - for (let idx in values) { - let value = values[idx]; - - let field = frappe.get_meta(doc.document_type).fields.filter((df) => df.fieldname == value)[0]; - if (field) { - selected_fields.push({ - label: field.label, - fieldname: field.fieldname, - fieldtype: field.fieldtype - }); - } - } - - d.refresh(); - frappe.model.set_value(doctype, doc.name, 'selected_fields', JSON.stringify(selected_fields)); - }); - - d.hide(); - }); - - d.show(); - }, - - get_date_field_for_dt: function(frm, row) { - frm.call({ - method: 'get_date_field_for_dt', - doc: frm.doc, - args: { - document_type: row.document_type - }, - callback: function(data) { - if (data.message) { - frappe.model.set_value('Patient History Custom Document Type', - row.name, 'date_fieldname', data.message); - } - } - }); - } -}); - -frappe.ui.form.on('Patient History Custom Document Type', { - document_type: function(frm, cdt, cdn) { - let row = locals[cdt][cdn]; - if (row.document_type) { - frm.events.get_date_field_for_dt(frm, row); - } - }, - - add_edit_fields: function(frm, cdt, cdn) { - let row = locals[cdt][cdn]; - if (row.document_type) { - frm.events.field_selector(frm, row, 0); - } - } -}); - -frappe.ui.form.on('Patient History Standard Document Type', { - add_edit_fields: function(frm, cdt, cdn) { - let row = locals[cdt][cdn]; - if (row.document_type) { - frm.events.field_selector(frm, row); - } - } -}); diff --git a/erpnext/healthcare/doctype/patient_history_settings/patient_history_settings.json b/erpnext/healthcare/doctype/patient_history_settings/patient_history_settings.json deleted file mode 100644 index 143e2c91eb5..00000000000 --- a/erpnext/healthcare/doctype/patient_history_settings/patient_history_settings.json +++ /dev/null @@ -1,55 +0,0 @@ -{ - "actions": [], - "creation": "2020-11-25 13:41:37.675518", - "doctype": "DocType", - "editable_grid": 1, - "engine": "InnoDB", - "field_order": [ - "standard_doctypes", - "section_break_2", - "custom_doctypes" - ], - "fields": [ - { - "fieldname": "section_break_2", - "fieldtype": "Section Break" - }, - { - "fieldname": "custom_doctypes", - "fieldtype": "Table", - "label": "Custom Document Types", - "options": "Patient History Custom Document Type" - }, - { - "fieldname": "standard_doctypes", - "fieldtype": "Table", - "label": "Standard Document Types", - "options": "Patient History Standard Document Type", - "read_only": 1 - } - ], - "index_web_pages_for_search": 1, - "issingle": 1, - "links": [], - "modified": "2020-11-25 13:43:38.511771", - "modified_by": "Administrator", - "module": "Healthcare", - "name": "Patient History Settings", - "owner": "Administrator", - "permissions": [ - { - "create": 1, - "delete": 1, - "email": 1, - "print": 1, - "read": 1, - "role": "System Manager", - "share": 1, - "write": 1 - } - ], - "quick_entry": 1, - "sort_field": "modified", - "sort_order": "DESC", - "track_changes": 1 -} \ No newline at end of file diff --git a/erpnext/healthcare/doctype/patient_history_settings/patient_history_settings.py b/erpnext/healthcare/doctype/patient_history_settings/patient_history_settings.py deleted file mode 100644 index b763591d3ac..00000000000 --- a/erpnext/healthcare/doctype/patient_history_settings/patient_history_settings.py +++ /dev/null @@ -1,194 +0,0 @@ -# -*- coding: utf-8 -*- -# Copyright (c) 2020, Frappe Technologies Pvt. Ltd. and contributors -# For license information, please see license.txt - -from __future__ import unicode_literals - -import json - -import frappe -from frappe import _ -from frappe.model.document import Document -from frappe.utils import cint, cstr - -from erpnext.healthcare.page.patient_history.patient_history import get_patient_history_doctypes - - -class PatientHistorySettings(Document): - def validate(self): - self.validate_submittable_doctypes() - self.validate_date_fieldnames() - - def validate_submittable_doctypes(self): - for entry in self.custom_doctypes: - if not cint(frappe.db.get_value('DocType', entry.document_type, 'is_submittable')): - msg = _('Row #{0}: Document Type {1} is not submittable.').format( - entry.idx, frappe.bold(entry.document_type)) - msg += _('Patient Medical Record can only be created for submittable document types.') - frappe.throw(msg) - - def validate_date_fieldnames(self): - for entry in self.custom_doctypes: - field = frappe.get_meta(entry.document_type).get_field(entry.date_fieldname) - if not field: - frappe.throw(_('Row #{0}: No such Field named {1} found in the Document Type {2}.').format( - entry.idx, frappe.bold(entry.date_fieldname), frappe.bold(entry.document_type))) - - if field.fieldtype not in ['Date', 'Datetime']: - frappe.throw(_('Row #{0}: Field {1} in Document Type {2} is not a Date / Datetime field.').format( - entry.idx, frappe.bold(entry.date_fieldname), frappe.bold(entry.document_type))) - - @frappe.whitelist() - def get_doctype_fields(self, document_type, fields): - multicheck_fields = [] - doc_fields = frappe.get_meta(document_type).fields - - for field in doc_fields: - if field.fieldtype not in frappe.model.no_value_fields or \ - field.fieldtype in frappe.model.table_fields and not field.hidden: - multicheck_fields.append({ - 'label': field.label, - 'value': field.fieldname, - 'checked': 1 if field.fieldname in fields else 0 - }) - - return multicheck_fields - - @frappe.whitelist() - def get_date_field_for_dt(self, document_type): - meta = frappe.get_meta(document_type) - date_fields = meta.get('fields', { - 'fieldtype': ['in', ['Date', 'Datetime']] - }) - - if date_fields: - return date_fields[0].get('fieldname') - -def create_medical_record(doc, method=None): - medical_record_required = validate_medical_record_required(doc) - if not medical_record_required: - return - - if frappe.db.exists('Patient Medical Record', { 'reference_name': doc.name }): - return - - subject = set_subject_field(doc) - date_field = get_date_field(doc.doctype) - medical_record = frappe.new_doc('Patient Medical Record') - medical_record.patient = doc.patient - medical_record.subject = subject - medical_record.status = 'Open' - medical_record.communication_date = doc.get(date_field) - medical_record.reference_doctype = doc.doctype - medical_record.reference_name = doc.name - medical_record.reference_owner = doc.owner - medical_record.save(ignore_permissions=True) - - -def update_medical_record(doc, method=None): - medical_record_required = validate_medical_record_required(doc) - if not medical_record_required: - return - - medical_record_id = frappe.db.exists('Patient Medical Record', { 'reference_name': doc.name }) - - if medical_record_id: - subject = set_subject_field(doc) - frappe.db.set_value('Patient Medical Record', medical_record_id[0][0], 'subject', subject) - else: - create_medical_record(doc) - - -def delete_medical_record(doc, method=None): - medical_record_required = validate_medical_record_required(doc) - if not medical_record_required: - return - - record = frappe.db.exists('Patient Medical Record', { 'reference_name': doc.name }) - if record: - frappe.delete_doc('Patient Medical Record', record, force=1) - - -def set_subject_field(doc): - from frappe.utils.formatters import format_value - - meta = frappe.get_meta(doc.doctype) - subject = '' - patient_history_fields = get_patient_history_fields(doc) - - for entry in patient_history_fields: - fieldname = entry.get('fieldname') - if entry.get('fieldtype') == 'Table' and doc.get(fieldname): - formatted_value = get_formatted_value_for_table_field(doc.get(fieldname), meta.get_field(fieldname)) - subject += frappe.bold(_(entry.get('label')) + ':') + '
' + cstr(formatted_value) + '
' - - else: - if doc.get(fieldname): - formatted_value = format_value(doc.get(fieldname), meta.get_field(fieldname), doc) - subject += frappe.bold(_(entry.get('label')) + ':') + cstr(formatted_value) + '
' - - return subject - - -def get_date_field(doctype): - dt = get_patient_history_config_dt(doctype) - - return frappe.db.get_value(dt, { 'document_type': doctype }, 'date_fieldname') - - -def get_patient_history_fields(doc): - dt = get_patient_history_config_dt(doc.doctype) - patient_history_fields = frappe.db.get_value(dt, { 'document_type': doc.doctype }, 'selected_fields') - - if patient_history_fields: - return json.loads(patient_history_fields) - - -def get_formatted_value_for_table_field(items, df): - child_meta = frappe.get_meta(df.options) - - table_head = '' - table_row = '' - html = '' - create_head = True - for item in items: - table_row += '
' + cdf.label + '' + str(item.get(cdf.fieldname)) + '
" + table_head + table_row + "
" - - return html - - -def get_patient_history_config_dt(doctype): - if frappe.db.get_value('DocType', doctype, 'custom'): - return 'Patient History Custom Document Type' - else: - return 'Patient History Standard Document Type' - - -def validate_medical_record_required(doc): - if frappe.flags.in_patch or frappe.flags.in_install or frappe.flags.in_setup_wizard \ - or get_module(doc) != 'Healthcare': - return False - - if doc.doctype not in get_patient_history_doctypes(): - return False - - return True - -def get_module(doc): - module = doc.meta.module - if not module: - module = frappe.db.get_value('DocType', doc.doctype, 'module') - - return module diff --git a/erpnext/healthcare/doctype/patient_history_settings/test_patient_history_settings.py b/erpnext/healthcare/doctype/patient_history_settings/test_patient_history_settings.py deleted file mode 100644 index c37a2adc368..00000000000 --- a/erpnext/healthcare/doctype/patient_history_settings/test_patient_history_settings.py +++ /dev/null @@ -1,106 +0,0 @@ -# -*- coding: utf-8 -*- -# Copyright (c) 2020, Frappe Technologies Pvt. Ltd. and Contributors -# See license.txt -from __future__ import unicode_literals - -import json -import unittest - -import frappe -from frappe.utils import getdate, strip_html - -from erpnext.healthcare.doctype.patient_appointment.test_patient_appointment import create_patient - - -class TestPatientHistorySettings(unittest.TestCase): - def setUp(self): - dt = create_custom_doctype() - settings = frappe.get_single("Patient History Settings") - settings.append("custom_doctypes", { - "document_type": dt.name, - "date_fieldname": "date", - "selected_fields": json.dumps([{ - "label": "Date", - "fieldname": "date", - "fieldtype": "Date" - }, - { - "label": "Rating", - "fieldname": "rating", - "fieldtype": "Rating" - }, - { - "label": "Feedback", - "fieldname": "feedback", - "fieldtype": "Small Text" - }]) - }) - settings.save() - - def test_custom_doctype_medical_record(self): - # tests for medical record creation of standard doctypes in test_patient_medical_record.py - patient = create_patient() - doc = create_doc(patient) - # check for medical record - medical_rec = frappe.db.exists("Patient Medical Record", {"status": "Open", "reference_name": doc.name}) - self.assertTrue(medical_rec) - - medical_rec = frappe.get_doc("Patient Medical Record", medical_rec) - expected_subject = "Date:{0}Rating:3Feedback:Test Patient History Settings".format( - frappe.utils.format_date(getdate())) - self.assertEqual(strip_html(medical_rec.subject), expected_subject) - self.assertEqual(medical_rec.patient, patient) - self.assertEqual(medical_rec.communication_date, getdate()) - - -def create_custom_doctype(): - if not frappe.db.exists("DocType", "Test Patient Feedback"): - doc = frappe.get_doc({ - "doctype": "DocType", - "module": "Healthcare", - "custom": 1, - "is_submittable": 1, - "fields": [{ - "label": "Date", - "fieldname": "date", - "fieldtype": "Date" - }, - { - "label": "Patient", - "fieldname": "patient", - "fieldtype": "Link", - "options": "Patient" - }, - { - "label": "Rating", - "fieldname": "rating", - "fieldtype": "Rating" - }, - { - "label": "Feedback", - "fieldname": "feedback", - "fieldtype": "Small Text" - }], - "permissions": [{ - "role": "System Manager", - "read": 1 - }], - "name": "Test Patient Feedback", - }) - doc.insert() - return doc - else: - return frappe.get_doc("DocType", "Test Patient Feedback") - - -def create_doc(patient): - doc = frappe.get_doc({ - "doctype": "Test Patient Feedback", - "patient": patient, - "date": getdate(), - "rating": 3, - "feedback": "Test Patient History Settings" - }).insert() - doc.submit() - - return doc diff --git a/erpnext/healthcare/doctype/patient_history_standard_document_type/__init__.py b/erpnext/healthcare/doctype/patient_history_standard_document_type/__init__.py deleted file mode 100644 index e69de29bb2d..00000000000 diff --git a/erpnext/healthcare/doctype/patient_history_standard_document_type/patient_history_standard_document_type.json b/erpnext/healthcare/doctype/patient_history_standard_document_type/patient_history_standard_document_type.json deleted file mode 100644 index b43099c4ea9..00000000000 --- a/erpnext/healthcare/doctype/patient_history_standard_document_type/patient_history_standard_document_type.json +++ /dev/null @@ -1,57 +0,0 @@ -{ - "actions": [], - "creation": "2020-11-25 13:39:36.014814", - "doctype": "DocType", - "editable_grid": 1, - "engine": "InnoDB", - "field_order": [ - "document_type", - "date_fieldname", - "add_edit_fields", - "selected_fields" - ], - "fields": [ - { - "fieldname": "document_type", - "fieldtype": "Link", - "in_list_view": 1, - "label": "Document Type", - "options": "DocType", - "read_only": 1, - "reqd": 1 - }, - { - "fieldname": "selected_fields", - "fieldtype": "Code", - "label": "Selected Fields", - "read_only": 1 - }, - { - "fieldname": "add_edit_fields", - "fieldtype": "Button", - "in_list_view": 1, - "label": "Add / Edit Fields" - }, - { - "fieldname": "date_fieldname", - "fieldtype": "Data", - "in_list_view": 1, - "label": "Date Fieldname", - "read_only": 1, - "reqd": 1 - } - ], - "index_web_pages_for_search": 1, - "istable": 1, - "links": [], - "modified": "2020-11-30 13:54:56.773325", - "modified_by": "Administrator", - "module": "Healthcare", - "name": "Patient History Standard Document Type", - "owner": "Administrator", - "permissions": [], - "quick_entry": 1, - "sort_field": "modified", - "sort_order": "DESC", - "track_changes": 1 -} \ No newline at end of file diff --git a/erpnext/healthcare/doctype/patient_history_standard_document_type/patient_history_standard_document_type.py b/erpnext/healthcare/doctype/patient_history_standard_document_type/patient_history_standard_document_type.py deleted file mode 100644 index b7dd09bc10c..00000000000 --- a/erpnext/healthcare/doctype/patient_history_standard_document_type/patient_history_standard_document_type.py +++ /dev/null @@ -1,12 +0,0 @@ -# -*- coding: utf-8 -*- -# Copyright (c) 2020, Frappe Technologies Pvt. Ltd. and contributors -# For license information, please see license.txt - -from __future__ import unicode_literals - -# import frappe -from frappe.model.document import Document - - -class PatientHistoryStandardDocumentType(Document): - pass diff --git a/erpnext/healthcare/doctype/patient_medical_record/__init__.py b/erpnext/healthcare/doctype/patient_medical_record/__init__.py deleted file mode 100644 index e69de29bb2d..00000000000 diff --git a/erpnext/healthcare/doctype/patient_medical_record/patient_medical_record.js b/erpnext/healthcare/doctype/patient_medical_record/patient_medical_record.js deleted file mode 100644 index 93ff70e6437..00000000000 --- a/erpnext/healthcare/doctype/patient_medical_record/patient_medical_record.js +++ /dev/null @@ -1,5 +0,0 @@ -// Copyright (c) 2016, ESS LLP and contributors -// For license information, please see license.txt - -frappe.ui.form.on('Patient Medical Record', { -}); diff --git a/erpnext/healthcare/doctype/patient_medical_record/patient_medical_record.json b/erpnext/healthcare/doctype/patient_medical_record/patient_medical_record.json deleted file mode 100644 index ed82355f33a..00000000000 --- a/erpnext/healthcare/doctype/patient_medical_record/patient_medical_record.json +++ /dev/null @@ -1,155 +0,0 @@ -{ - "actions": [], - "allow_copy": 1, - "allow_import": 1, - "autoname": "naming_series:", - "beta": 1, - "creation": "2016-06-09 11:30:44.972056", - "doctype": "DocType", - "document_type": "Setup", - "engine": "InnoDB", - "field_order": [ - "naming_series", - "patient", - "status", - "column_break_2", - "attach", - "section_break_4", - "subject", - "section_break_8", - "communication_date", - "reference_doctype", - "reference_name", - "column_break_9", - "reference_owner", - "user" - ], - "fields": [ - { - "fieldname": "naming_series", - "fieldtype": "Select", - "label": "Series", - "options": "HLC-PMR-.YYYY.-", - "print_hide": 1, - "report_hide": 1 - }, - { - "fieldname": "patient", - "fieldtype": "Link", - "ignore_user_permissions": 1, - "in_list_view": 1, - "label": "Patient", - "options": "Patient", - "search_index": 1 - }, - { - "fieldname": "column_break_2", - "fieldtype": "Column Break" - }, - { - "fieldname": "attach", - "fieldtype": "Attach", - "label": "Attach Medical Record" - }, - { - "fieldname": "section_break_4", - "fieldtype": "Section Break" - }, - { - "fieldname": "subject", - "fieldtype": "Text Editor", - "ignore_xss_filter": 1, - "label": "Subject" - }, - { - "fieldname": "status", - "fieldtype": "Select", - "label": "Status", - "options": "Open\nClose", - "read_only": 1 - }, - { - "default": "Today", - "fieldname": "communication_date", - "fieldtype": "Date", - "in_list_view": 1, - "label": "Datetime", - "read_only": 1 - }, - { - "fieldname": "reference_doctype", - "fieldtype": "Link", - "in_list_view": 1, - "label": "Reference DocType", - "options": "DocType", - "read_only": 1, - "search_index": 1 - }, - { - "fieldname": "reference_name", - "fieldtype": "Dynamic Link", - "in_list_view": 1, - "label": "Reference Name", - "options": "reference_doctype", - "read_only": 1, - "search_index": 1 - }, - { - "fetch_from": "reference_name.owner", - "fieldname": "reference_owner", - "fieldtype": "Data", - "label": "Reference Owner", - "no_copy": 1, - "print_hide": 1, - "read_only": 1, - "report_hide": 1 - }, - { - "default": "__user", - "fieldname": "user", - "fieldtype": "Link", - "label": "User", - "options": "User", - "print_hide": 1, - "read_only": 1, - "report_hide": 1 - }, - { - "fieldname": "column_break_9", - "fieldtype": "Column Break" - }, - { - "fieldname": "section_break_8", - "fieldtype": "Section Break" - } - ], - "in_create": 1, - "links": [], - "modified": "2020-04-29 12:26:57.679402", - "modified_by": "Administrator", - "module": "Healthcare", - "name": "Patient Medical Record", - "owner": "Administrator", - "permissions": [ - { - "create": 1, - "delete": 1, - "email": 1, - "export": 1, - "print": 1, - "read": 1, - "report": 1, - "role": "Physician", - "share": 1, - "write": 1 - } - ], - "restrict_to_domain": "Healthcare", - "search_fields": "patient, subject, communication_date, reference_doctype, reference_name", - "show_name_in_global_search": 1, - "sort_field": "modified", - "sort_order": "DESC", - "title_field": "patient", - "track_changes": 1, - "track_seen": 1 -} \ No newline at end of file diff --git a/erpnext/healthcare/doctype/patient_medical_record/patient_medical_record.py b/erpnext/healthcare/doctype/patient_medical_record/patient_medical_record.py deleted file mode 100644 index ac2cffa3e89..00000000000 --- a/erpnext/healthcare/doctype/patient_medical_record/patient_medical_record.py +++ /dev/null @@ -1,14 +0,0 @@ -# -*- coding: utf-8 -*- -# Copyright (c) 2015, ESS LLP and contributors -# For license information, please see license.txt - -from __future__ import unicode_literals - -import frappe -from frappe.model.document import Document - - -class PatientMedicalRecord(Document): - def after_insert(self): - if self.reference_doctype == "Patient Medical Record" : - frappe.db.set_value("Patient Medical Record", self.name, "reference_name", self.name) diff --git a/erpnext/healthcare/doctype/patient_medical_record/test_patient_medical_record.py b/erpnext/healthcare/doctype/patient_medical_record/test_patient_medical_record.py deleted file mode 100644 index 099146c7ee7..00000000000 --- a/erpnext/healthcare/doctype/patient_medical_record/test_patient_medical_record.py +++ /dev/null @@ -1,101 +0,0 @@ -# -*- coding: utf-8 -*- -# Copyright (c) 2015, ESS LLP and Contributors -# See license.txt -from __future__ import unicode_literals - -import unittest - -import frappe -from frappe.utils import nowdate - -from erpnext.accounts.doctype.pos_profile.test_pos_profile import make_pos_profile -from erpnext.healthcare.doctype.patient_appointment.test_patient_appointment import ( - create_appointment, - create_encounter, - create_healthcare_docs, - create_medical_department, -) - - -class TestPatientMedicalRecord(unittest.TestCase): - def setUp(self): - frappe.db.set_value('Healthcare Settings', None, 'enable_free_follow_ups', 0) - frappe.db.set_value('Healthcare Settings', None, 'automate_appointment_invoicing', 1) - make_pos_profile() - - def test_medical_record(self): - patient, practitioner = create_healthcare_docs() - medical_department = create_medical_department() - appointment = create_appointment(patient, practitioner, nowdate(), invoice=1) - encounter = create_encounter(appointment) - - # check for encounter - medical_rec = frappe.db.exists('Patient Medical Record', {'status': 'Open', 'reference_name': encounter.name}) - self.assertTrue(medical_rec) - - vital_signs = create_vital_signs(appointment) - # check for vital signs - medical_rec = frappe.db.exists('Patient Medical Record', {'status': 'Open', 'reference_name': vital_signs.name}) - self.assertTrue(medical_rec) - - appointment = create_appointment(patient, practitioner, nowdate(), invoice=1, procedure_template=1) - procedure = create_procedure(appointment) - procedure.start_procedure() - procedure.complete_procedure() - # check for clinical procedure - medical_rec = frappe.db.exists('Patient Medical Record', {'status': 'Open', 'reference_name': procedure.name}) - self.assertTrue(medical_rec) - - template = create_lab_test_template(medical_department) - lab_test = create_lab_test(template.name, patient) - # check for lab test - medical_rec = frappe.db.exists('Patient Medical Record', {'status': 'Open', 'reference_name': lab_test.name}) - self.assertTrue(medical_rec) - - -def create_procedure(appointment): - if appointment: - procedure = frappe.new_doc('Clinical Procedure') - procedure.procedure_template = appointment.procedure_template - procedure.appointment = appointment.name - procedure.patient = appointment.patient - procedure.practitioner = appointment.practitioner - procedure.medical_department = appointment.department - procedure.start_dt = appointment.appointment_date - procedure.start_time = appointment.appointment_time - procedure.save() - procedure.submit() - return procedure - -def create_vital_signs(appointment): - vital_signs = frappe.new_doc('Vital Signs') - vital_signs.patient = appointment.patient - vital_signs.signs_date = appointment.appointment_date - vital_signs.signs_time = appointment.appointment_time - vital_signs.temperature = 38.5 - vital_signs.save() - vital_signs.submit() - return vital_signs - -def create_lab_test_template(medical_department): - if frappe.db.exists('Lab Test Template', 'Blood Test'): - return frappe.get_doc('Lab Test Template', 'Blood Test') - - template = frappe.new_doc('Lab Test Template') - template.lab_test_name = 'Blood Test' - template.lab_test_code = 'Blood Test' - template.lab_test_group = 'Services' - template.department = medical_department - template.is_billable = 1 - template.lab_test_rate = 2000 - template.save() - return template - -def create_lab_test(template, patient): - lab_test = frappe.new_doc('Lab Test') - lab_test.patient = patient - lab_test.patient_sex = frappe.db.get_value('Patient', patient, 'sex') - lab_test.template = template - lab_test.save() - lab_test.submit() - return lab_test diff --git a/erpnext/healthcare/doctype/patient_relation/__init__.py b/erpnext/healthcare/doctype/patient_relation/__init__.py deleted file mode 100644 index e69de29bb2d..00000000000 diff --git a/erpnext/healthcare/doctype/patient_relation/patient_relation.json b/erpnext/healthcare/doctype/patient_relation/patient_relation.json deleted file mode 100644 index 376f7f76d66..00000000000 --- a/erpnext/healthcare/doctype/patient_relation/patient_relation.json +++ /dev/null @@ -1,52 +0,0 @@ -{ - "actions": [], - "allow_copy": 1, - "beta": 1, - "creation": "2017-04-26 15:40:11.561855", - "doctype": "DocType", - "editable_grid": 1, - "engine": "InnoDB", - "field_order": [ - "patient", - "relation", - "description" - ], - "fields": [ - { - "fieldname": "relation", - "fieldtype": "Select", - "in_list_view": 1, - "label": "Relation", - "options": "\nFather\nMother\nSpouse\nSiblings\nFamily\nOther", - "search_index": 1 - }, - { - "fieldname": "patient", - "fieldtype": "Link", - "ignore_user_permissions": 1, - "in_list_view": 1, - "label": "Patient", - "options": "Patient", - "reqd": 1 - }, - { - "fieldname": "description", - "fieldtype": "Small Text", - "ignore_xss_filter": 1, - "label": "Description" - } - ], - "istable": 1, - "links": [], - "modified": "2020-01-29 12:45:40.081899", - "modified_by": "Administrator", - "module": "Healthcare", - "name": "Patient Relation", - "owner": "Administrator", - "permissions": [], - "quick_entry": 1, - "restrict_to_domain": "Healthcare", - "sort_field": "modified", - "sort_order": "DESC", - "track_changes": 1 -} \ No newline at end of file diff --git a/erpnext/healthcare/doctype/patient_relation/patient_relation.py b/erpnext/healthcare/doctype/patient_relation/patient_relation.py deleted file mode 100644 index 17bc20940d6..00000000000 --- a/erpnext/healthcare/doctype/patient_relation/patient_relation.py +++ /dev/null @@ -1,11 +0,0 @@ -# -*- coding: utf-8 -*- -# Copyright (c) 2017, ESS LLP and contributors -# For license information, please see license.txt - -from __future__ import unicode_literals - -from frappe.model.document import Document - - -class PatientRelation(Document): - pass diff --git a/erpnext/healthcare/doctype/practitioner_schedule/__init__.py b/erpnext/healthcare/doctype/practitioner_schedule/__init__.py deleted file mode 100644 index e69de29bb2d..00000000000 diff --git a/erpnext/healthcare/doctype/practitioner_schedule/practitioner_schedule.js b/erpnext/healthcare/doctype/practitioner_schedule/practitioner_schedule.js deleted file mode 100644 index 7cb7c4b65e6..00000000000 --- a/erpnext/healthcare/doctype/practitioner_schedule/practitioner_schedule.js +++ /dev/null @@ -1,117 +0,0 @@ -// Copyright (c) 2018, Frappe Technologies Pvt. Ltd. and contributors -// For license information, please see license.txt - -frappe.ui.form.on('Practitioner Schedule', { - refresh: function(frm) { - cur_frm.fields_dict["time_slots"].grid.wrapper.find('.grid-add-row').hide(); - cur_frm.fields_dict["time_slots"].grid.add_custom_button(__('Add Time Slots'), () => { - let d = new frappe.ui.Dialog({ - fields: [ - {fieldname: 'days', label: __('Select Days'), fieldtype: 'MultiSelect', - options:[ - {value:'Sunday', label:__('Sunday')}, - {value:'Monday', label:__('Monday')}, - {value:'Tuesday', label:__('Tuesday')}, - {value:'Wednesday', label:__('Wednesday')}, - {value:'Thursday', label:__('Thursday')}, - {value:'Friday', label:__('Friday')}, - {value:'Saturday', label:__('Saturday')}, - ], reqd: 1}, - {fieldname: 'from_time', label: __('From'), fieldtype: 'Time', - 'default': '09:00:00', reqd: 1}, - {fieldname: 'to_time', label: __('To'), fieldtype: 'Time', - 'default': '12:00:00', reqd: 1}, - {fieldname: 'duration', label: __('Appointment Duration (mins)'), - fieldtype:'Int', 'default': 15, reqd: 1}, - ], - primary_action_label: __('Add Timeslots'), - primary_action: () => { - let values = d.get_values(); - if (values) { - let slot_added = false; - values.days.split(',').forEach(function(day){ - day = $.trim(day); - if (['Sunday', 'Monday', 'Tuesday', 'Wednesday', - 'Thursday', 'Friday', 'Saturday'].includes(day)){ - add_slots(day); - } - }); - - function check_overlap_or_add_slot(week_day, cur_time, end_time, add_slots_to_child){ - let overlap = false; - while (cur_time < end_time) { - let add_to_child = true; - let to_time = cur_time.clone().add(values.duration, 'minutes'); - if (to_time <= end_time) { - if (frm.doc.time_slots){ - frm.doc.time_slots.forEach(function(slot) { - if (slot.day == week_day){ - let slot_from_moment = moment(slot.from_time, 'HH:mm:ss'); - let slot_to_moment = moment(slot.to_time, 'HH:mm:ss'); - if (cur_time.isSame(slot_from_moment) || cur_time.isBetween(slot_from_moment, slot_to_moment) || - to_time.isSame(slot_to_moment) || to_time.isBetween(slot_from_moment, slot_to_moment)) { - overlap = true; - if (add_slots_to_child) { - frappe.show_alert({ - message:__('Time slot skiped, the slot {0} to {1} overlap exisiting slot {2} to {3}', - [cur_time.format('HH:mm:ss'), to_time.format('HH:mm:ss'), slot.from_time, slot.to_time]), - indicator:'orange' - }); - add_to_child = false; - } - } - } - }); - } - // add a new timeslot - if (add_to_child && add_slots_to_child) { - frm.add_child('time_slots', { - from_time: cur_time.format('HH:mm:ss'), - to_time: to_time.format('HH:mm:ss'), - day: week_day - }); - slot_added = true; - } - } - cur_time = to_time; - } - return overlap; - } - - function add_slots(week_day) { - let cur_time = moment(values.from_time, 'HH:mm:ss'); - let end_time = moment(values.to_time, 'HH:mm:ss'); - if (check_overlap_or_add_slot(week_day, cur_time, end_time, false)) { - frappe.confirm(__('Schedules for {0} overlaps, do you want to proceed after skiping overlaped slots ?', [week_day]), - function() { - // if Yes - check_overlap_or_add_slot(week_day, cur_time, end_time, true); - }, - function() { - // if No - frappe.show_alert({ - message: __('Slots for {0} are not added to the schedule', [week_day]), - indicator: 'red' - }); - } - ); - } else { - check_overlap_or_add_slot(week_day, cur_time, end_time, true); - } - } - - frm.refresh_field('time_slots'); - - if (slot_added) { - frappe.show_alert({ - message: __('Time slots added'), - indicator: 'green' - }); - } - } - }, - }); - d.show(); - }); - } -}); diff --git a/erpnext/healthcare/doctype/practitioner_schedule/practitioner_schedule.json b/erpnext/healthcare/doctype/practitioner_schedule/practitioner_schedule.json deleted file mode 100644 index a21825ea8e7..00000000000 --- a/erpnext/healthcare/doctype/practitioner_schedule/practitioner_schedule.json +++ /dev/null @@ -1,71 +0,0 @@ -{ - "actions": [], - "allow_import": 1, - "allow_rename": 1, - "autoname": "field:schedule_name", - "beta": 1, - "creation": "2017-05-03 17:28:03.926787", - "doctype": "DocType", - "editable_grid": 1, - "engine": "InnoDB", - "field_order": [ - "disabled", - "schedule_details_section", - "schedule_name", - "time_slots" - ], - "fields": [ - { - "fieldname": "schedule_name", - "fieldtype": "Data", - "ignore_xss_filter": 1, - "in_list_view": 1, - "label": "Schedule Name", - "reqd": 1, - "unique": 1 - }, - { - "fieldname": "time_slots", - "fieldtype": "Table", - "label": "Time Slots", - "options": "Healthcare Schedule Time Slot" - }, - { - "default": "0", - "fieldname": "disabled", - "fieldtype": "Check", - "label": "Disabled", - "print_hide": 1 - }, - { - "fieldname": "schedule_details_section", - "fieldtype": "Section Break", - "label": "Schedule Details" - } - ], - "links": [], - "modified": "2020-09-18 17:26:09.703215", - "modified_by": "Administrator", - "module": "Healthcare", - "name": "Practitioner Schedule", - "owner": "Administrator", - "permissions": [ - { - "create": 1, - "delete": 1, - "email": 1, - "export": 1, - "print": 1, - "read": 1, - "report": 1, - "role": "Healthcare Administrator", - "share": 1, - "write": 1 - } - ], - "restrict_to_domain": "Healthcare", - "show_name_in_global_search": 1, - "sort_field": "modified", - "sort_order": "DESC", - "track_changes": 1 -} \ No newline at end of file diff --git a/erpnext/healthcare/doctype/practitioner_schedule/practitioner_schedule.py b/erpnext/healthcare/doctype/practitioner_schedule/practitioner_schedule.py deleted file mode 100644 index 7fa31e5fb67..00000000000 --- a/erpnext/healthcare/doctype/practitioner_schedule/practitioner_schedule.py +++ /dev/null @@ -1,12 +0,0 @@ -# -*- coding: utf-8 -*- -# Copyright (c) 2018, Frappe Technologies Pvt. Ltd. and contributors -# For license information, please see license.txt - -from __future__ import unicode_literals - -from frappe.model.document import Document - - -class PractitionerSchedule(Document): - def autoname(self): - self.name = self.schedule_name diff --git a/erpnext/healthcare/doctype/practitioner_schedule/test_practitioner_schedule.py b/erpnext/healthcare/doctype/practitioner_schedule/test_practitioner_schedule.py deleted file mode 100644 index 1ecaa47248a..00000000000 --- a/erpnext/healthcare/doctype/practitioner_schedule/test_practitioner_schedule.py +++ /dev/null @@ -1,10 +0,0 @@ -# -*- coding: utf-8 -*- -# Copyright (c) 2018, Frappe Technologies Pvt. Ltd. and Contributors -# See license.txt -from __future__ import unicode_literals - -import unittest - - -class TestPractitionerSchedule(unittest.TestCase): - pass diff --git a/erpnext/healthcare/doctype/practitioner_service_unit_schedule/__init__.py b/erpnext/healthcare/doctype/practitioner_service_unit_schedule/__init__.py deleted file mode 100644 index e69de29bb2d..00000000000 diff --git a/erpnext/healthcare/doctype/practitioner_service_unit_schedule/practitioner_service_unit_schedule.json b/erpnext/healthcare/doctype/practitioner_service_unit_schedule/practitioner_service_unit_schedule.json deleted file mode 100644 index 4c283aaf1e4..00000000000 --- a/erpnext/healthcare/doctype/practitioner_service_unit_schedule/practitioner_service_unit_schedule.json +++ /dev/null @@ -1,110 +0,0 @@ -{ - "allow_copy": 0, - "allow_events_in_timeline": 0, - "allow_guest_to_view": 0, - "allow_import": 0, - "allow_rename": 0, - "beta": 1, - "creation": "2017-11-16 12:19:17.163786", - "custom": 0, - "docstatus": 0, - "doctype": "DocType", - "document_type": "", - "editable_grid": 1, - "engine": "InnoDB", - "fields": [ - { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "schedule", - "fieldtype": "Link", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 1, - "in_standard_filter": 0, - "label": "Schedule", - "length": 0, - "no_copy": 0, - "options": "Practitioner Schedule", - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 1, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 - }, - { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "service_unit", - "fieldtype": "Link", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 1, - "in_standard_filter": 0, - "label": "Service Unit", - "length": 0, - "no_copy": 0, - "options": "Healthcare Service Unit", - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 - } - ], - "has_web_view": 0, - "hide_heading": 0, - "hide_toolbar": 0, - "idx": 0, - "image_view": 0, - "in_create": 0, - "is_submittable": 0, - "issingle": 0, - "istable": 1, - "max_attachments": 0, - "modified": "2018-11-04 03:33:07.936958", - "modified_by": "Administrator", - "module": "Healthcare", - "name": "Practitioner Service Unit Schedule", - "name_case": "", - "owner": "Administrator", - "permissions": [], - "quick_entry": 1, - "read_only": 0, - "read_only_onload": 0, - "restrict_to_domain": "Healthcare", - "show_name_in_global_search": 0, - "sort_field": "modified", - "sort_order": "DESC", - "track_changes": 1, - "track_seen": 0, - "track_views": 0 -} \ No newline at end of file diff --git a/erpnext/healthcare/doctype/practitioner_service_unit_schedule/practitioner_service_unit_schedule.py b/erpnext/healthcare/doctype/practitioner_service_unit_schedule/practitioner_service_unit_schedule.py deleted file mode 100644 index 4eba1fbf6b4..00000000000 --- a/erpnext/healthcare/doctype/practitioner_service_unit_schedule/practitioner_service_unit_schedule.py +++ /dev/null @@ -1,11 +0,0 @@ -# -*- coding: utf-8 -*- -# Copyright (c) 2018, Frappe Technologies Pvt. Ltd. and contributors -# For license information, please see license.txt - -from __future__ import unicode_literals - -from frappe.model.document import Document - - -class PractitionerServiceUnitSchedule(Document): - pass diff --git a/erpnext/healthcare/doctype/prescription_dosage/__init__.py b/erpnext/healthcare/doctype/prescription_dosage/__init__.py deleted file mode 100644 index e69de29bb2d..00000000000 diff --git a/erpnext/healthcare/doctype/prescription_dosage/prescription_dosage.js b/erpnext/healthcare/doctype/prescription_dosage/prescription_dosage.js deleted file mode 100644 index 94b444cbaa2..00000000000 --- a/erpnext/healthcare/doctype/prescription_dosage/prescription_dosage.js +++ /dev/null @@ -1,5 +0,0 @@ -// Copyright (c) 2017, Frappe Technologies Pvt. Ltd. and contributors -// For license information, please see license.txt - -frappe.ui.form.on('Prescription Dosage', { -}); diff --git a/erpnext/healthcare/doctype/prescription_dosage/prescription_dosage.json b/erpnext/healthcare/doctype/prescription_dosage/prescription_dosage.json deleted file mode 100644 index 9fb0dbc13ca..00000000000 --- a/erpnext/healthcare/doctype/prescription_dosage/prescription_dosage.json +++ /dev/null @@ -1,145 +0,0 @@ -{ - "allow_copy": 0, - "allow_guest_to_view": 0, - "allow_import": 1, - "allow_rename": 1, - "autoname": "field:dosage", - "beta": 1, - "creation": "2016-09-16 15:49:25.327610", - "custom": 0, - "docstatus": 0, - "doctype": "DocType", - "document_type": "Document", - "editable_grid": 0, - "fields": [ - { - "allow_bulk_edit": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "dosage", - "fieldtype": "Data", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 1, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 1, - "in_standard_filter": 0, - "label": "Dosage", - "length": 0, - "no_copy": 0, - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 1, - "search_index": 0, - "set_only_once": 0, - "unique": 0 - }, - { - "allow_bulk_edit": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "dosage_strength", - "fieldtype": "Table", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "length": 0, - "no_copy": 0, - "options": "Dosage Strength", - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "unique": 0 - } - ], - "has_web_view": 0, - "hide_heading": 0, - "hide_toolbar": 0, - "idx": 0, - "image_view": 0, - "in_create": 0, - "is_submittable": 0, - "issingle": 0, - "istable": 0, - "max_attachments": 0, - "modified": "2017-10-05 11:20:47.558464", - "modified_by": "Administrator", - "module": "Healthcare", - "name": "Prescription Dosage", - "name_case": "", - "owner": "Administrator", - "permissions": [ - { - "amend": 0, - "apply_user_permissions": 0, - "cancel": 0, - "create": 1, - "delete": 1, - "email": 1, - "export": 1, - "if_owner": 0, - "import": 0, - "permlevel": 0, - "print": 1, - "read": 1, - "report": 1, - "role": "Healthcare Administrator", - "set_user_permissions": 0, - "share": 1, - "submit": 0, - "write": 1 - }, - { - "amend": 0, - "apply_user_permissions": 0, - "cancel": 0, - "create": 1, - "delete": 1, - "email": 1, - "export": 1, - "if_owner": 0, - "import": 0, - "permlevel": 0, - "print": 1, - "read": 1, - "report": 1, - "role": "Physician", - "set_user_permissions": 0, - "share": 1, - "submit": 0, - "write": 1 - } - ], - "quick_entry": 0, - "read_only": 0, - "read_only_onload": 0, - "restrict_to_domain": "Healthcare", - "search_fields": "dosage", - "show_name_in_global_search": 0, - "sort_field": "modified", - "sort_order": "DESC", - "title_field": "", - "track_changes": 1, - "track_seen": 0 -} \ No newline at end of file diff --git a/erpnext/healthcare/doctype/prescription_dosage/prescription_dosage.py b/erpnext/healthcare/doctype/prescription_dosage/prescription_dosage.py deleted file mode 100644 index 19f9b70bb61..00000000000 --- a/erpnext/healthcare/doctype/prescription_dosage/prescription_dosage.py +++ /dev/null @@ -1,11 +0,0 @@ -# -*- coding: utf-8 -*- -# Copyright (c) 2017, Frappe Technologies Pvt. Ltd. and contributors -# For license information, please see license.txt - -from __future__ import unicode_literals - -from frappe.model.document import Document - - -class PrescriptionDosage(Document): - pass diff --git a/erpnext/healthcare/doctype/prescription_dosage/test_prescription_dosage.py b/erpnext/healthcare/doctype/prescription_dosage/test_prescription_dosage.py deleted file mode 100644 index cabfd35e23d..00000000000 --- a/erpnext/healthcare/doctype/prescription_dosage/test_prescription_dosage.py +++ /dev/null @@ -1,10 +0,0 @@ -# -*- coding: utf-8 -*- -# Copyright (c) 2017, Frappe Technologies Pvt. Ltd. and Contributors -# See license.txt -from __future__ import unicode_literals - -import unittest - - -class TestPrescriptionDosage(unittest.TestCase): - pass diff --git a/erpnext/healthcare/doctype/prescription_duration/__init__.py b/erpnext/healthcare/doctype/prescription_duration/__init__.py deleted file mode 100644 index e69de29bb2d..00000000000 diff --git a/erpnext/healthcare/doctype/prescription_duration/prescription_duration.js b/erpnext/healthcare/doctype/prescription_duration/prescription_duration.js deleted file mode 100644 index dd5887c9296..00000000000 --- a/erpnext/healthcare/doctype/prescription_duration/prescription_duration.js +++ /dev/null @@ -1,5 +0,0 @@ -// Copyright (c) 2017, Frappe Technologies Pvt. Ltd. and contributors -// For license information, please see license.txt - -frappe.ui.form.on('Prescription Duration', { -}); diff --git a/erpnext/healthcare/doctype/prescription_duration/prescription_duration.json b/erpnext/healthcare/doctype/prescription_duration/prescription_duration.json deleted file mode 100644 index c4f6c5f10da..00000000000 --- a/erpnext/healthcare/doctype/prescription_duration/prescription_duration.json +++ /dev/null @@ -1,145 +0,0 @@ -{ - "allow_copy": 1, - "allow_guest_to_view": 0, - "allow_import": 1, - "allow_rename": 1, - "autoname": "", - "beta": 1, - "creation": "2016-09-16 15:50:28.895789", - "custom": 0, - "docstatus": 0, - "doctype": "DocType", - "document_type": "Document", - "editable_grid": 0, - "fields": [ - { - "allow_bulk_edit": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "number", - "fieldtype": "Int", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 1, - "in_standard_filter": 0, - "label": "Number", - "length": 0, - "no_copy": 0, - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 1, - "search_index": 0, - "set_only_once": 0, - "unique": 0 - }, - { - "allow_bulk_edit": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "period", - "fieldtype": "Select", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 1, - "in_standard_filter": 0, - "label": "Period", - "length": 0, - "no_copy": 0, - "options": "Hour\nDay\nWeek\nMonth", - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 1, - "search_index": 0, - "set_only_once": 0, - "unique": 0 - } - ], - "has_web_view": 0, - "hide_heading": 0, - "hide_toolbar": 0, - "idx": 0, - "image_view": 0, - "in_create": 0, - "is_submittable": 0, - "issingle": 0, - "istable": 0, - "max_attachments": 0, - "modified": "2017-08-31 13:42:51.325725", - "modified_by": "Administrator", - "module": "Healthcare", - "name": "Prescription Duration", - "name_case": "", - "owner": "Administrator", - "permissions": [ - { - "amend": 0, - "apply_user_permissions": 0, - "cancel": 0, - "create": 1, - "delete": 1, - "email": 1, - "export": 1, - "if_owner": 0, - "import": 0, - "permlevel": 0, - "print": 1, - "read": 1, - "report": 1, - "role": "Healthcare Administrator", - "set_user_permissions": 0, - "share": 1, - "submit": 0, - "write": 1 - }, - { - "amend": 0, - "apply_user_permissions": 0, - "cancel": 0, - "create": 1, - "delete": 1, - "email": 1, - "export": 1, - "if_owner": 0, - "import": 0, - "permlevel": 0, - "print": 1, - "read": 1, - "report": 1, - "role": "Physician", - "set_user_permissions": 0, - "share": 1, - "submit": 0, - "write": 1 - } - ], - "quick_entry": 1, - "read_only": 0, - "read_only_onload": 0, - "restrict_to_domain": "Healthcare", - "search_fields": "", - "show_name_in_global_search": 0, - "sort_field": "", - "sort_order": "ASC", - "track_changes": 1, - "track_seen": 0 -} \ No newline at end of file diff --git a/erpnext/healthcare/doctype/prescription_duration/prescription_duration.py b/erpnext/healthcare/doctype/prescription_duration/prescription_duration.py deleted file mode 100644 index 988276da748..00000000000 --- a/erpnext/healthcare/doctype/prescription_duration/prescription_duration.py +++ /dev/null @@ -1,74 +0,0 @@ -# -*- coding: utf-8 -*- -# Copyright (c) 2017, Frappe Technologies Pvt. Ltd. and contributors -# For license information, please see license.txt - -from __future__ import unicode_literals - -from frappe.model.document import Document -from frappe.utils import cstr - - -class PrescriptionDuration(Document): - def autoname(self): - self.name = " ".join(filter(None, - [cstr(self.get(f)).strip() for f in ["number", "period"]])) - def get_days(self): - days = 0 - duration = self - if(duration.period == 'Day'): - days = duration.number - if(duration.period == 'Hour'): - days = (duration.number)/24 - if(duration.period == 'Week'): - days = (duration.number*7) - if(duration.period == 'Month'): - days = (duration.number*30) - return days - def get_weeks(self): - weeks = 0 - duration = self - if(duration.period == 'Day'): - weeks = (duration.number)/7 - #if(duration.period == 'Hour'): - # weeks = (duration.number)/x - if(duration.period == 'Week'): - weeks = duration.number - if(duration.period == 'Month'): - weeks = duration.number*4 - return weeks - def get_months(self): - months = 0 - duration = self - if(duration.period == 'Day'): - months = (duration.number)/30 - #if(duration.period == 'Hour'): - # months = (duration.number)/x - if(duration.period == 'Week'): - months = (duration.number)/4 - if(duration.period == 'Month'): - months = duration.number - return months - def get_hours(self): - hours = 0 - duration = self - if(duration.period == 'Day'): - hours = (duration.number*24) - if(duration.period == 'Hour'): - hours = duration.number - if(duration.period == 'Week'): - hours = (duration.number*24)*7 - if(duration.period == 'Month'): - hours = (duration.number*24)*30 - return hours - def get_minutes(self): - minutes = 0 - duration = self - if(duration.period == 'Day'): - minutes = (duration.number*1440) - if(duration.period == 'Hour'): - minutes = (duration.number*60) - if(duration.period == 'Week'): - minutes = (duration.number*10080) - if(duration.period == 'Month'): - minutes = (duration.number*43800) - return minutes diff --git a/erpnext/healthcare/doctype/prescription_duration/test_prescription_duration.py b/erpnext/healthcare/doctype/prescription_duration/test_prescription_duration.py deleted file mode 100644 index 197bb3e7fb9..00000000000 --- a/erpnext/healthcare/doctype/prescription_duration/test_prescription_duration.py +++ /dev/null @@ -1,10 +0,0 @@ -# -*- coding: utf-8 -*- -# Copyright (c) 2017, Frappe Technologies Pvt. Ltd. and Contributors -# See license.txt -from __future__ import unicode_literals - -import unittest - - -class TestPrescriptionDuration(unittest.TestCase): - pass diff --git a/erpnext/healthcare/doctype/procedure_prescription/__init__.py b/erpnext/healthcare/doctype/procedure_prescription/__init__.py deleted file mode 100644 index e69de29bb2d..00000000000 diff --git a/erpnext/healthcare/doctype/procedure_prescription/procedure_prescription.json b/erpnext/healthcare/doctype/procedure_prescription/procedure_prescription.json deleted file mode 100644 index e4c01d79c10..00000000000 --- a/erpnext/healthcare/doctype/procedure_prescription/procedure_prescription.json +++ /dev/null @@ -1,99 +0,0 @@ -{ - "actions": [], - "allow_copy": 1, - "beta": 1, - "creation": "2017-11-17 15:52:48.324157", - "doctype": "DocType", - "editable_grid": 1, - "engine": "InnoDB", - "field_order": [ - "procedure", - "procedure_name", - "department", - "practitioner", - "date", - "comments", - "appointment_booked", - "procedure_created", - "invoiced" - ], - "fields": [ - { - "fieldname": "procedure", - "fieldtype": "Link", - "in_list_view": 1, - "label": "Clinical Procedure", - "options": "Clinical Procedure Template", - "reqd": 1 - }, - { - "fetch_from": "procedure.template", - "fieldname": "procedure_name", - "fieldtype": "Data", - "in_list_view": 1, - "label": "Procedure Name" - }, - { - "fetch_from": "procedure.medical_department", - "fieldname": "department", - "fieldtype": "Link", - "label": "Department", - "options": "Medical Department" - }, - { - "fieldname": "practitioner", - "fieldtype": "Link", - "in_list_view": 1, - "label": "Referring Practitioner", - "options": "Healthcare Practitioner" - }, - { - "fieldname": "date", - "fieldtype": "Date", - "in_list_view": 1, - "label": "Date" - }, - { - "fieldname": "comments", - "fieldtype": "Data", - "label": "Comments" - }, - { - "default": "0", - "fieldname": "appointment_booked", - "fieldtype": "Check", - "hidden": 1, - "label": "Appointment Booked", - "search_index": 1 - }, - { - "default": "0", - "fieldname": "procedure_created", - "fieldtype": "Check", - "hidden": 1, - "label": "Procedure Created", - "no_copy": 1, - "search_index": 1 - }, - { - "default": "0", - "fieldname": "invoiced", - "fieldtype": "Check", - "label": "Invoiced", - "read_only": 1, - "search_index": 1 - } - ], - "istable": 1, - "links": [], - "modified": "2020-02-26 15:42:33.988081", - "modified_by": "Administrator", - "module": "Healthcare", - "name": "Procedure Prescription", - "owner": "Administrator", - "permissions": [], - "restrict_to_domain": "Healthcare", - "sort_field": "modified", - "sort_order": "DESC", - "track_changes": 1 -} \ No newline at end of file diff --git a/erpnext/healthcare/doctype/procedure_prescription/procedure_prescription.py b/erpnext/healthcare/doctype/procedure_prescription/procedure_prescription.py deleted file mode 100644 index f4d29fa6a30..00000000000 --- a/erpnext/healthcare/doctype/procedure_prescription/procedure_prescription.py +++ /dev/null @@ -1,11 +0,0 @@ -# -*- coding: utf-8 -*- -# Copyright (c) 2017, Frappe Technologies Pvt. Ltd. and contributors -# For license information, please see license.txt - -from __future__ import unicode_literals - -from frappe.model.document import Document - - -class ProcedurePrescription(Document): - pass diff --git a/erpnext/healthcare/doctype/sample_collection/__init__.py b/erpnext/healthcare/doctype/sample_collection/__init__.py deleted file mode 100644 index e69de29bb2d..00000000000 diff --git a/erpnext/healthcare/doctype/sample_collection/sample_collection.js b/erpnext/healthcare/doctype/sample_collection/sample_collection.js deleted file mode 100644 index ddf8285bc6d..00000000000 --- a/erpnext/healthcare/doctype/sample_collection/sample_collection.js +++ /dev/null @@ -1,40 +0,0 @@ -// Copyright (c) 2016, ESS and contributors -// For license information, please see license.txt - -frappe.ui.form.on('Sample Collection', { - refresh: function(frm) { - if (frappe.defaults.get_default('create_sample_collection_for_lab_test')) { - frm.add_custom_button(__('View Lab Tests'), function() { - frappe.route_options = {'sample': frm.doc.name}; - frappe.set_route('List', 'Lab Test'); - }); - } - } -}); - -frappe.ui.form.on('Sample Collection', 'patient', function(frm) { - if(frm.doc.patient){ - frappe.call({ - 'method': 'erpnext.healthcare.doctype.patient.patient.get_patient_detail', - args: { - patient: frm.doc.patient - }, - callback: function (data) { - var age = null; - if (data.message.dob){ - age = calculate_age(data.message.dob); - } - frappe.model.set_value(frm.doctype,frm.docname, 'patient_age', age); - frappe.model.set_value(frm.doctype,frm.docname, 'patient_sex', data.message.sex); - } - }); - } -}); - -var calculate_age = function(birth) { - var ageMS = Date.parse(Date()) - Date.parse(birth); - var age = new Date(); - age.setTime(ageMS); - var years = age.getFullYear() - 1970; - return `${years} ${__('Years(s)')} ${age.getMonth()} ${__('Month(s)')} ${age.getDate()} ${__('Day(s)')}`; -}; diff --git a/erpnext/healthcare/doctype/sample_collection/sample_collection.json b/erpnext/healthcare/doctype/sample_collection/sample_collection.json deleted file mode 100644 index 83383e34457..00000000000 --- a/erpnext/healthcare/doctype/sample_collection/sample_collection.json +++ /dev/null @@ -1,256 +0,0 @@ -{ - "actions": [], - "allow_copy": 1, - "allow_import": 1, - "autoname": "naming_series:", - "beta": 1, - "creation": "2016-04-05 15:58:18.076977", - "doctype": "DocType", - "document_type": "Document", - "engine": "InnoDB", - "field_order": [ - "patient_details_section", - "naming_series", - "patient", - "patient_name", - "patient_age", - "patient_sex", - "column_break_4", - "inpatient_record", - "company", - "invoiced", - "section_break_6", - "sample", - "sample_uom", - "sample_qty", - "column_break_10", - "collected_by", - "collected_time", - "num_print", - "section_break_15", - "sample_details", - "amended_from" - ], - "fields": [ - { - "fetch_from": "patient.inpatient_record", - "fieldname": "inpatient_record", - "fieldtype": "Link", - "hide_days": 1, - "hide_seconds": 1, - "label": "Inpatient Record", - "options": "Inpatient Record", - "read_only": 1 - }, - { - "bold": 1, - "fieldname": "naming_series", - "fieldtype": "Select", - "hide_days": 1, - "hide_seconds": 1, - "label": "Series", - "no_copy": 1, - "options": "HLC-SC-.YYYY.-", - "print_hide": 1, - "reqd": 1 - }, - { - "default": "0", - "fieldname": "invoiced", - "fieldtype": "Check", - "hide_days": 1, - "hide_seconds": 1, - "label": "Invoiced", - "no_copy": 1, - "read_only": 1, - "search_index": 1 - }, - { - "fetch_from": "inpatient_record.patient", - "fieldname": "patient", - "fieldtype": "Link", - "hide_days": 1, - "hide_seconds": 1, - "ignore_user_permissions": 1, - "in_standard_filter": 1, - "label": "Patient", - "options": "Patient", - "reqd": 1, - "search_index": 1 - }, - { - "fieldname": "column_break_4", - "fieldtype": "Column Break", - "hide_days": 1, - "hide_seconds": 1 - }, - { - "fieldname": "patient_age", - "fieldtype": "Data", - "hide_days": 1, - "hide_seconds": 1, - "label": "Age", - "read_only": 1 - }, - { - "fetch_from": "patient.sex", - "fieldname": "patient_sex", - "fieldtype": "Link", - "hide_days": 1, - "hide_seconds": 1, - "label": "Gender", - "options": "Gender", - "read_only": 1 - }, - { - "fieldname": "company", - "fieldtype": "Link", - "hide_days": 1, - "hide_seconds": 1, - "in_standard_filter": 1, - "label": "Company", - "options": "Company" - }, - { - "fieldname": "section_break_6", - "fieldtype": "Section Break", - "hide_days": 1, - "hide_seconds": 1, - "label": "Sample Details" - }, - { - "fieldname": "sample", - "fieldtype": "Link", - "hide_days": 1, - "hide_seconds": 1, - "ignore_user_permissions": 1, - "in_list_view": 1, - "in_standard_filter": 1, - "label": "Sample", - "options": "Lab Test Sample", - "reqd": 1, - "search_index": 1 - }, - { - "fetch_from": "sample.sample_uom", - "fieldname": "sample_uom", - "fieldtype": "Data", - "hide_days": 1, - "hide_seconds": 1, - "in_list_view": 1, - "label": "UOM", - "read_only": 1 - }, - { - "fieldname": "column_break_10", - "fieldtype": "Column Break", - "hide_days": 1, - "hide_seconds": 1 - }, - { - "fieldname": "collected_by", - "fieldtype": "Link", - "hide_days": 1, - "hide_seconds": 1, - "ignore_user_permissions": 1, - "label": "Collected By", - "options": "User" - }, - { - "fieldname": "collected_time", - "fieldtype": "Datetime", - "hide_days": 1, - "hide_seconds": 1, - "label": "Collected On" - }, - { - "allow_on_submit": 1, - "default": "1", - "description": "Number of prints required for labelling the samples", - "fieldname": "num_print", - "fieldtype": "Int", - "hide_days": 1, - "hide_seconds": 1, - "label": "No. of prints", - "print_hide": 1, - "report_hide": 1 - }, - { - "fieldname": "amended_from", - "fieldtype": "Link", - "hide_days": 1, - "hide_seconds": 1, - "label": "Amended From", - "no_copy": 1, - "options": "Sample Collection", - "print_hide": 1, - "read_only": 1 - }, - { - "fieldname": "section_break_15", - "fieldtype": "Section Break", - "hide_days": 1, - "hide_seconds": 1 - }, - { - "default": "0", - "fieldname": "sample_qty", - "fieldtype": "Float", - "hide_days": 1, - "hide_seconds": 1, - "in_list_view": 1, - "label": "Quantity" - }, - { - "fieldname": "sample_details", - "fieldtype": "Long Text", - "hide_days": 1, - "hide_seconds": 1, - "ignore_xss_filter": 1, - "label": "Collection Details" - }, - { - "fieldname": "patient_details_section", - "fieldtype": "Section Break", - "label": "Patient Details" - }, - { - "fetch_from": "patient.patient_name", - "fieldname": "patient_name", - "fieldtype": "Data", - "label": "Patient Name", - "read_only": 1 - } - ], - "is_submittable": 1, - "links": [], - "modified": "2020-07-30 16:53:13.076104", - "modified_by": "Administrator", - "module": "Healthcare", - "name": "Sample Collection", - "owner": "Administrator", - "permissions": [ - { - "amend": 1, - "cancel": 1, - "create": 1, - "email": 1, - "export": 1, - "print": 1, - "read": 1, - "report": 1, - "role": "Laboratory User", - "share": 1, - "submit": 1, - "write": 1 - } - ], - "restrict_to_domain": "Healthcare", - "search_fields": "patient, sample", - "show_name_in_global_search": 1, - "sort_field": "modified", - "sort_order": "DESC", - "title_field": "patient", - "track_changes": 1, - "track_seen": 1 -} \ No newline at end of file diff --git a/erpnext/healthcare/doctype/sample_collection/sample_collection.py b/erpnext/healthcare/doctype/sample_collection/sample_collection.py deleted file mode 100644 index 7de6ac08ca1..00000000000 --- a/erpnext/healthcare/doctype/sample_collection/sample_collection.py +++ /dev/null @@ -1,16 +0,0 @@ -# -*- coding: utf-8 -*- -# Copyright (c) 2015, ESS and contributors -# For license information, please see license.txt - -from __future__ import unicode_literals - -import frappe -from frappe import _ -from frappe.model.document import Document -from frappe.utils import flt - - -class SampleCollection(Document): - def validate(self): - if flt(self.sample_qty) <= 0: - frappe.throw(_('Sample Quantity cannot be negative or 0'), title=_('Invalid Quantity')) diff --git a/erpnext/healthcare/doctype/sample_collection/test_sample_collection.py b/erpnext/healthcare/doctype/sample_collection/test_sample_collection.py deleted file mode 100644 index 0b16173dd53..00000000000 --- a/erpnext/healthcare/doctype/sample_collection/test_sample_collection.py +++ /dev/null @@ -1,11 +0,0 @@ -# -*- coding: utf-8 -*- -# Copyright (c) 2015, ESS and Contributors -# See license.txt -from __future__ import unicode_literals - -import unittest - -# test_records = frappe.get_test_records('Sample Collection') - -class TestSampleCollection(unittest.TestCase): - pass diff --git a/erpnext/healthcare/doctype/sensitivity/__init__.py b/erpnext/healthcare/doctype/sensitivity/__init__.py deleted file mode 100644 index e69de29bb2d..00000000000 diff --git a/erpnext/healthcare/doctype/sensitivity/sensitivity.js b/erpnext/healthcare/doctype/sensitivity/sensitivity.js deleted file mode 100644 index f9c9002fe6d..00000000000 --- a/erpnext/healthcare/doctype/sensitivity/sensitivity.js +++ /dev/null @@ -1,5 +0,0 @@ -// Copyright (c) 2016, ESS LLP and contributors -// For license information, please see license.txt - -frappe.ui.form.on('Sensitivity', { -}); diff --git a/erpnext/healthcare/doctype/sensitivity/sensitivity.json b/erpnext/healthcare/doctype/sensitivity/sensitivity.json deleted file mode 100644 index eddfda90566..00000000000 --- a/erpnext/healthcare/doctype/sensitivity/sensitivity.json +++ /dev/null @@ -1,115 +0,0 @@ -{ - "allow_copy": 1, - "allow_guest_to_view": 0, - "allow_import": 1, - "allow_rename": 1, - "autoname": "field:sensitivity", - "beta": 1, - "creation": "2016-02-23 11:12:54.623249", - "custom": 0, - "docstatus": 0, - "doctype": "DocType", - "document_type": "Setup", - "editable_grid": 0, - "fields": [ - { - "allow_bulk_edit": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "sensitivity", - "fieldtype": "Data", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 1, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 1, - "in_standard_filter": 0, - "label": "Sensitivity", - "length": 0, - "no_copy": 0, - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 1, - "search_index": 0, - "set_only_once": 0, - "unique": 0 - } - ], - "has_web_view": 0, - "hide_heading": 0, - "hide_toolbar": 0, - "idx": 0, - "image_view": 0, - "in_create": 0, - "is_submittable": 0, - "issingle": 0, - "istable": 0, - "max_attachments": 0, - "modified": "2017-10-05 11:19:12.110308", - "modified_by": "Administrator", - "module": "Healthcare", - "name": "Sensitivity", - "name_case": "", - "owner": "Administrator", - "permissions": [ - { - "amend": 0, - "apply_user_permissions": 0, - "cancel": 0, - "create": 0, - "delete": 0, - "email": 1, - "export": 1, - "if_owner": 0, - "import": 0, - "permlevel": 0, - "print": 1, - "read": 1, - "report": 1, - "role": "Laboratory User", - "set_user_permissions": 0, - "share": 1, - "submit": 0, - "write": 0 - }, - { - "amend": 0, - "apply_user_permissions": 0, - "cancel": 0, - "create": 1, - "delete": 1, - "email": 1, - "export": 1, - "if_owner": 0, - "import": 0, - "permlevel": 0, - "print": 1, - "read": 1, - "report": 1, - "role": "Healthcare Administrator", - "set_user_permissions": 0, - "share": 1, - "submit": 0, - "write": 1 - } - ], - "quick_entry": 1, - "read_only": 0, - "read_only_onload": 0, - "restrict_to_domain": "Healthcare", - "search_fields": "sensitivity", - "show_name_in_global_search": 0, - "sort_field": "modified", - "sort_order": "DESC", - "title_field": "sensitivity", - "track_changes": 1, - "track_seen": 0 -} \ No newline at end of file diff --git a/erpnext/healthcare/doctype/sensitivity/sensitivity.py b/erpnext/healthcare/doctype/sensitivity/sensitivity.py deleted file mode 100644 index f61781d3f86..00000000000 --- a/erpnext/healthcare/doctype/sensitivity/sensitivity.py +++ /dev/null @@ -1,11 +0,0 @@ -# -*- coding: utf-8 -*- -# Copyright (c) 2015, ESS and contributors -# For license information, please see license.txt - -from __future__ import unicode_literals - -from frappe.model.document import Document - - -class Sensitivity(Document): - pass diff --git a/erpnext/healthcare/doctype/sensitivity/test_sensitivity.py b/erpnext/healthcare/doctype/sensitivity/test_sensitivity.py deleted file mode 100644 index c772c72faf0..00000000000 --- a/erpnext/healthcare/doctype/sensitivity/test_sensitivity.py +++ /dev/null @@ -1,11 +0,0 @@ -# -*- coding: utf-8 -*- -# Copyright (c) 2015, ESS and Contributors -# See license.txt -from __future__ import unicode_literals - -import unittest - -# test_records = frappe.get_test_records('Sensitivity') - -class TestSensitivity(unittest.TestCase): - pass diff --git a/erpnext/healthcare/doctype/sensitivity_test_result/__init__.py b/erpnext/healthcare/doctype/sensitivity_test_result/__init__.py deleted file mode 100644 index e69de29bb2d..00000000000 diff --git a/erpnext/healthcare/doctype/sensitivity_test_result/sensitivity_test_result.json b/erpnext/healthcare/doctype/sensitivity_test_result/sensitivity_test_result.json deleted file mode 100644 index 768c17710fe..00000000000 --- a/erpnext/healthcare/doctype/sensitivity_test_result/sensitivity_test_result.json +++ /dev/null @@ -1,103 +0,0 @@ -{ - "allow_copy": 1, - "allow_guest_to_view": 0, - "allow_import": 0, - "allow_rename": 0, - "beta": 1, - "creation": "2016-02-22 15:18:01.769903", - "custom": 0, - "docstatus": 0, - "doctype": "DocType", - "document_type": "Document", - "editable_grid": 1, - "fields": [ - { - "allow_bulk_edit": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "antibiotic", - "fieldtype": "Link", - "hidden": 0, - "ignore_user_permissions": 1, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 1, - "in_standard_filter": 0, - "label": "Antibiotic", - "length": 0, - "no_copy": 0, - "options": "Antibiotic", - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "unique": 0 - }, - { - "allow_bulk_edit": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "antibiotic_sensitivity", - "fieldtype": "Link", - "hidden": 0, - "ignore_user_permissions": 1, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 1, - "in_standard_filter": 0, - "label": "Sensitivity", - "length": 0, - "no_copy": 0, - "options": "Sensitivity", - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "unique": 0 - } - ], - "has_web_view": 0, - "hide_heading": 0, - "hide_toolbar": 0, - "idx": 0, - "image_view": 0, - "in_create": 0, - "is_submittable": 0, - "issingle": 0, - "istable": 1, - "max_attachments": 0, - "modified": "2017-10-05 11:08:06.327972", - "modified_by": "Administrator", - "module": "Healthcare", - "name": "Sensitivity Test Result", - "name_case": "", - "owner": "Administrator", - "permissions": [], - "quick_entry": 0, - "read_only": 0, - "read_only_onload": 0, - "restrict_to_domain": "Healthcare", - "show_name_in_global_search": 0, - "sort_field": "modified", - "sort_order": "DESC", - "track_changes": 0, - "track_seen": 0 -} \ No newline at end of file diff --git a/erpnext/healthcare/doctype/sensitivity_test_result/sensitivity_test_result.py b/erpnext/healthcare/doctype/sensitivity_test_result/sensitivity_test_result.py deleted file mode 100644 index 53f7acc4af0..00000000000 --- a/erpnext/healthcare/doctype/sensitivity_test_result/sensitivity_test_result.py +++ /dev/null @@ -1,11 +0,0 @@ -# -*- coding: utf-8 -*- -# Copyright (c) 2015, ESS and contributors -# For license information, please see license.txt - -from __future__ import unicode_literals - -from frappe.model.document import Document - - -class SensitivityTestResult(Document): - pass diff --git a/erpnext/healthcare/doctype/therapy_plan/__init__.py b/erpnext/healthcare/doctype/therapy_plan/__init__.py deleted file mode 100644 index e69de29bb2d..00000000000 diff --git a/erpnext/healthcare/doctype/therapy_plan/test_therapy_plan.py b/erpnext/healthcare/doctype/therapy_plan/test_therapy_plan.py deleted file mode 100644 index 4f96f6a7066..00000000000 --- a/erpnext/healthcare/doctype/therapy_plan/test_therapy_plan.py +++ /dev/null @@ -1,118 +0,0 @@ -# -*- coding: utf-8 -*- -# Copyright (c) 2020, Frappe Technologies Pvt. Ltd. and Contributors -# See license.txt -from __future__ import unicode_literals - -import unittest - -import frappe -from frappe.utils import flt, getdate, nowdate - -from erpnext.healthcare.doctype.patient_appointment.test_patient_appointment import ( - create_appointment, - create_healthcare_docs, - create_medical_department, - create_patient, -) -from erpnext.healthcare.doctype.therapy_plan.therapy_plan import ( - make_sales_invoice, - make_therapy_session, -) -from erpnext.healthcare.doctype.therapy_type.test_therapy_type import create_therapy_type - - -class TestTherapyPlan(unittest.TestCase): - def test_creation_on_encounter_submission(self): - patient, practitioner = create_healthcare_docs() - medical_department = create_medical_department() - encounter = create_encounter(patient, medical_department, practitioner) - self.assertTrue(frappe.db.exists('Therapy Plan', encounter.therapy_plan)) - - def test_status(self): - plan = create_therapy_plan() - self.assertEqual(plan.status, 'Not Started') - - session = make_therapy_session(plan.name, plan.patient, 'Basic Rehab', '_Test Company') - frappe.get_doc(session).submit() - self.assertEqual(frappe.db.get_value('Therapy Plan', plan.name, 'status'), 'In Progress') - - session = make_therapy_session(plan.name, plan.patient, 'Basic Rehab', '_Test Company') - frappe.get_doc(session).submit() - self.assertEqual(frappe.db.get_value('Therapy Plan', plan.name, 'status'), 'Completed') - - patient, practitioner = create_healthcare_docs() - appointment = create_appointment(patient, practitioner, nowdate()) - - session = make_therapy_session(plan.name, plan.patient, 'Basic Rehab', '_Test Company', appointment.name) - session = frappe.get_doc(session) - session.submit() - self.assertEqual(frappe.db.get_value('Patient Appointment', appointment.name, 'status'), 'Closed') - session.cancel() - self.assertEqual(frappe.db.get_value('Patient Appointment', appointment.name, 'status'), 'Open') - - def test_therapy_plan_from_template(self): - patient = create_patient() - template = create_therapy_plan_template() - # check linked item - self.assertTrue(frappe.db.exists('Therapy Plan Template', {'linked_item': 'Complete Rehab'})) - - plan = create_therapy_plan(template) - # invoice - si = make_sales_invoice(plan.name, patient, '_Test Company', template) - si.save() - - therapy_plan_template_amt = frappe.db.get_value('Therapy Plan Template', template, 'total_amount') - self.assertEqual(si.items[0].amount, therapy_plan_template_amt) - - -def create_therapy_plan(template=None): - patient = create_patient() - therapy_type = create_therapy_type() - plan = frappe.new_doc('Therapy Plan') - plan.patient = patient - plan.start_date = getdate() - - if template: - plan.therapy_plan_template = template - plan = plan.set_therapy_details_from_template() - else: - plan.append('therapy_plan_details', { - 'therapy_type': therapy_type.name, - 'no_of_sessions': 2 - }) - - plan.save() - return plan - -def create_encounter(patient, medical_department, practitioner): - encounter = frappe.new_doc('Patient Encounter') - encounter.patient = patient - encounter.practitioner = practitioner - encounter.medical_department = medical_department - therapy_type = create_therapy_type() - encounter.append('therapies', { - 'therapy_type': therapy_type.name, - 'no_of_sessions': 2 - }) - encounter.save() - encounter.submit() - return encounter - -def create_therapy_plan_template(): - template_name = frappe.db.exists('Therapy Plan Template', 'Complete Rehab') - if not template_name: - therapy_type = create_therapy_type() - template = frappe.new_doc('Therapy Plan Template') - template.plan_name = template.item_code = template.item_name = 'Complete Rehab' - template.item_group = 'Services' - rate = frappe.db.get_value('Therapy Type', therapy_type.name, 'rate') - template.append('therapy_types', { - 'therapy_type': therapy_type.name, - 'no_of_sessions': 2, - 'rate': rate, - 'amount': 2 * flt(rate) - }) - template.save() - template_name = template.name - - return template_name diff --git a/erpnext/healthcare/doctype/therapy_plan/therapy_plan.js b/erpnext/healthcare/doctype/therapy_plan/therapy_plan.js deleted file mode 100644 index 42e231dc662..00000000000 --- a/erpnext/healthcare/doctype/therapy_plan/therapy_plan.js +++ /dev/null @@ -1,133 +0,0 @@ -// Copyright (c) 2020, Frappe Technologies Pvt. Ltd. and contributors -// For license information, please see license.txt - -frappe.ui.form.on('Therapy Plan', { - setup: function(frm) { - frm.get_field('therapy_plan_details').grid.editable_fields = [ - {fieldname: 'therapy_type', columns: 6}, - {fieldname: 'no_of_sessions', columns: 2}, - {fieldname: 'sessions_completed', columns: 2} - ]; - }, - - refresh: function(frm) { - if (!frm.doc.__islocal) { - frm.trigger('show_progress_for_therapies'); - if (frm.doc.status != 'Completed') { - let therapy_types = (frm.doc.therapy_plan_details || []).map(function(d){ return d.therapy_type; }); - const fields = [{ - fieldtype: 'Link', - label: __('Therapy Type'), - fieldname: 'therapy_type', - options: 'Therapy Type', - reqd: 1, - get_query: function() { - return { - filters: { 'therapy_type': ['in', therapy_types]} - }; - } - }]; - - frm.add_custom_button(__('Therapy Session'), function() { - frappe.prompt(fields, data => { - frappe.call({ - method: 'erpnext.healthcare.doctype.therapy_plan.therapy_plan.make_therapy_session', - args: { - therapy_plan: frm.doc.name, - patient: frm.doc.patient, - therapy_type: data.therapy_type, - company: frm.doc.company - }, - freeze: true, - callback: function(r) { - if (r.message) { - frappe.model.sync(r.message); - frappe.set_route('Form', r.message.doctype, r.message.name); - } - } - }); - }, __('Select Therapy Type'), __('Create')); - }, __('Create')); - } - - if (frm.doc.therapy_plan_template && !frm.doc.invoiced) { - frm.add_custom_button(__('Sales Invoice'), function() { - frm.trigger('make_sales_invoice'); - }, __('Create')); - } - } - - if (frm.doc.therapy_plan_template) { - frm.fields_dict.therapy_plan_details.grid.update_docfield_property( - 'therapy_type', 'read_only', 1 - ); - frm.fields_dict.therapy_plan_details.grid.update_docfield_property( - 'no_of_sessions', 'read_only', 1 - ); - } - }, - - make_sales_invoice: function(frm) { - frappe.call({ - args: { - 'reference_name': frm.doc.name, - 'patient': frm.doc.patient, - 'company': frm.doc.company, - 'therapy_plan_template': frm.doc.therapy_plan_template - }, - method: 'erpnext.healthcare.doctype.therapy_plan.therapy_plan.make_sales_invoice', - callback: function(r) { - var doclist = frappe.model.sync(r.message); - frappe.set_route('Form', doclist[0].doctype, doclist[0].name); - } - }); - }, - - therapy_plan_template: function(frm) { - if (frm.doc.therapy_plan_template) { - frappe.call({ - method: 'set_therapy_details_from_template', - doc: frm.doc, - freeze: true, - freeze_message: __('Fetching Template Details'), - callback: function() { - refresh_field('therapy_plan_details'); - } - }); - } - }, - - show_progress_for_therapies: function(frm) { - let bars = []; - let message = ''; - - // completed sessions - let title = __('{0} sessions completed', [frm.doc.total_sessions_completed]); - if (frm.doc.total_sessions_completed === 1) { - title = __('{0} session completed', [frm.doc.total_sessions_completed]); - } - title += __(' out of {0}', [frm.doc.total_sessions]); - - bars.push({ - 'title': title, - 'width': (frm.doc.total_sessions_completed / frm.doc.total_sessions * 100) + '%', - 'progress_class': 'progress-bar-success' - }); - if (bars[0].width == '0%') { - bars[0].width = '0.5%'; - } - message = title; - frm.dashboard.add_progress(__('Status'), bars, message); - }, -}); - -frappe.ui.form.on('Therapy Plan Detail', { - no_of_sessions: function(frm) { - let total = 0; - $.each(frm.doc.therapy_plan_details, function(_i, e) { - total += e.no_of_sessions; - }); - frm.set_value('total_sessions', total); - refresh_field('total_sessions'); - } -}); diff --git a/erpnext/healthcare/doctype/therapy_plan/therapy_plan.json b/erpnext/healthcare/doctype/therapy_plan/therapy_plan.json deleted file mode 100644 index c03e9de3320..00000000000 --- a/erpnext/healthcare/doctype/therapy_plan/therapy_plan.json +++ /dev/null @@ -1,179 +0,0 @@ -{ - "actions": [], - "autoname": "naming_series:", - "creation": "2020-03-29 20:56:49.758602", - "doctype": "DocType", - "editable_grid": 1, - "engine": "InnoDB", - "field_order": [ - "naming_series", - "patient", - "patient_name", - "invoiced", - "column_break_4", - "company", - "status", - "start_date", - "section_break_3", - "therapy_plan_template", - "therapy_plan_details", - "title", - "section_break_9", - "total_sessions", - "column_break_11", - "total_sessions_completed" - ], - "fields": [ - { - "fieldname": "patient", - "fieldtype": "Link", - "in_list_view": 1, - "label": "Patient", - "options": "Patient", - "reqd": 1 - }, - { - "fieldname": "start_date", - "fieldtype": "Date", - "in_list_view": 1, - "label": "Start Date", - "reqd": 1 - }, - { - "fieldname": "section_break_3", - "fieldtype": "Section Break" - }, - { - "fieldname": "therapy_plan_details", - "fieldtype": "Table", - "label": "Therapy Plan Details", - "options": "Therapy Plan Detail", - "read_only_depends_on": "therapy_plan_template", - "reqd": 1 - }, - { - "fieldname": "naming_series", - "fieldtype": "Select", - "label": "Naming Series", - "options": "HLC-THP-.YYYY.-" - }, - { - "fetch_from": "patient.patient_name", - "fieldname": "patient_name", - "fieldtype": "Data", - "label": "Patient Name", - "read_only": 1 - }, - { - "default": "{patient_name}", - "fieldname": "title", - "fieldtype": "Data", - "hidden": 1, - "label": "Title", - "no_copy": 1 - }, - { - "fieldname": "column_break_4", - "fieldtype": "Column Break" - }, - { - "fieldname": "section_break_9", - "fieldtype": "Section Break" - }, - { - "fieldname": "total_sessions", - "fieldtype": "Int", - "label": "Total Sessions", - "read_only": 1 - }, - { - "fieldname": "column_break_11", - "fieldtype": "Column Break" - }, - { - "fieldname": "total_sessions_completed", - "fieldtype": "Int", - "label": "Total Sessions Completed", - "read_only": 1 - }, - { - "fieldname": "status", - "fieldtype": "Select", - "label": "Status", - "options": "Not Started\nIn Progress\nCompleted\nCancelled", - "read_only": 1 - }, - { - "fieldname": "company", - "fieldtype": "Link", - "in_standard_filter": 1, - "label": "Company", - "options": "Company", - "reqd": 1 - }, - { - "fieldname": "therapy_plan_template", - "fieldtype": "Link", - "label": "Therapy Plan Template", - "options": "Therapy Plan Template", - "set_only_once": 1 - }, - { - "default": "0", - "fieldname": "invoiced", - "fieldtype": "Check", - "label": "Invoiced", - "no_copy": 1, - "print_hide": 1, - "read_only": 1 - } - ], - "links": [], - "modified": "2020-11-04 18:13:13.564999", - "modified_by": "Administrator", - "module": "Healthcare", - "name": "Therapy Plan", - "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": "Healthcare Administrator", - "share": 1, - "write": 1 - }, - { - "email": 1, - "export": 1, - "print": 1, - "read": 1, - "report": 1, - "role": "Physician", - "share": 1, - "write": 1 - } - ], - "quick_entry": 1, - "search_fields": "patient", - "sort_field": "modified", - "sort_order": "DESC", - "title_field": "patient", - "track_changes": 1 -} \ No newline at end of file diff --git a/erpnext/healthcare/doctype/therapy_plan/therapy_plan.py b/erpnext/healthcare/doctype/therapy_plan/therapy_plan.py deleted file mode 100644 index 6d63f391895..00000000000 --- a/erpnext/healthcare/doctype/therapy_plan/therapy_plan.py +++ /dev/null @@ -1,103 +0,0 @@ -# -*- coding: utf-8 -*- -# Copyright (c) 2020, Frappe Technologies Pvt. Ltd. and contributors -# For license information, please see license.txt - -from __future__ import unicode_literals - -import frappe -from frappe.model.document import Document -from frappe.utils import flt, today - - -class TherapyPlan(Document): - def validate(self): - self.set_totals() - self.set_status() - - def set_status(self): - if not self.total_sessions_completed: - self.status = 'Not Started' - else: - if self.total_sessions_completed < self.total_sessions: - self.status = 'In Progress' - elif self.total_sessions_completed == self.total_sessions: - self.status = 'Completed' - - def set_totals(self): - total_sessions = 0 - total_sessions_completed = 0 - for entry in self.therapy_plan_details: - if entry.no_of_sessions: - total_sessions += entry.no_of_sessions - if entry.sessions_completed: - total_sessions_completed += entry.sessions_completed - - self.db_set('total_sessions', total_sessions) - self.db_set('total_sessions_completed', total_sessions_completed) - - @frappe.whitelist() - def set_therapy_details_from_template(self): - # Add therapy types in the child table - self.set('therapy_plan_details', []) - therapy_plan_template = frappe.get_doc('Therapy Plan Template', self.therapy_plan_template) - - for data in therapy_plan_template.therapy_types: - self.append('therapy_plan_details', { - 'therapy_type': data.therapy_type, - 'no_of_sessions': data.no_of_sessions - }) - return self - - -@frappe.whitelist() -def make_therapy_session(therapy_plan, patient, therapy_type, company, appointment=None): - therapy_type = frappe.get_doc('Therapy Type', therapy_type) - - therapy_session = frappe.new_doc('Therapy Session') - therapy_session.therapy_plan = therapy_plan - therapy_session.company = company - therapy_session.patient = patient - therapy_session.therapy_type = therapy_type.name - therapy_session.duration = therapy_type.default_duration - therapy_session.rate = therapy_type.rate - therapy_session.exercises = therapy_type.exercises - therapy_session.appointment = appointment - - if frappe.flags.in_test: - therapy_session.start_date = today() - return therapy_session.as_dict() - - -@frappe.whitelist() -def make_sales_invoice(reference_name, patient, company, therapy_plan_template): - from erpnext.stock.get_item_details import get_item_details - si = frappe.new_doc('Sales Invoice') - si.company = company - si.patient = patient - si.customer = frappe.db.get_value('Patient', patient, 'customer') - - item = frappe.db.get_value('Therapy Plan Template', therapy_plan_template, 'linked_item') - price_list, price_list_currency = frappe.db.get_values('Price List', {'selling': 1}, ['name', 'currency'])[0] - args = { - 'doctype': 'Sales Invoice', - 'item_code': item, - 'company': company, - 'customer': si.customer, - 'selling_price_list': price_list, - 'price_list_currency': price_list_currency, - 'plc_conversion_rate': 1.0, - 'conversion_rate': 1.0 - } - - item_line = si.append('items', {}) - item_details = get_item_details(args) - item_line.item_code = item - item_line.qty = 1 - item_line.rate = item_details.price_list_rate - item_line.amount = flt(item_line.rate) * flt(item_line.qty) - item_line.reference_dt = 'Therapy Plan' - item_line.reference_dn = reference_name - item_line.description = item_details.description - - si.set_missing_values(for_validate = True) - return si diff --git a/erpnext/healthcare/doctype/therapy_plan/therapy_plan_dashboard.py b/erpnext/healthcare/doctype/therapy_plan/therapy_plan_dashboard.py deleted file mode 100644 index 25c8df1d6b7..00000000000 --- a/erpnext/healthcare/doctype/therapy_plan/therapy_plan_dashboard.py +++ /dev/null @@ -1,23 +0,0 @@ -from __future__ import unicode_literals - -from frappe import _ - - -def get_data(): - return { - 'fieldname': 'therapy_plan', - 'non_standard_fieldnames': { - 'Sales Invoice': 'reference_dn' - }, - 'transactions': [ - { - 'label': _('Therapy Sessions'), - 'items': ['Therapy Session'] - }, - { - 'label': _('Billing'), - 'items': ['Sales Invoice'] - } - ], - 'disable_create_buttons': ['Sales Invoice'] - } diff --git a/erpnext/healthcare/doctype/therapy_plan/therapy_plan_list.js b/erpnext/healthcare/doctype/therapy_plan/therapy_plan_list.js deleted file mode 100644 index 63967aff33b..00000000000 --- a/erpnext/healthcare/doctype/therapy_plan/therapy_plan_list.js +++ /dev/null @@ -1,11 +0,0 @@ -frappe.listview_settings['Therapy Plan'] = { - get_indicator: function(doc) { - var colors = { - 'Completed': 'green', - 'In Progress': 'orange', - 'Not Started': 'red', - 'Cancelled': 'grey' - }; - return [__(doc.status), colors[doc.status], 'status,=,' + doc.status]; - } -}; diff --git a/erpnext/healthcare/doctype/therapy_plan_detail/__init__.py b/erpnext/healthcare/doctype/therapy_plan_detail/__init__.py deleted file mode 100644 index e69de29bb2d..00000000000 diff --git a/erpnext/healthcare/doctype/therapy_plan_detail/therapy_plan_detail.json b/erpnext/healthcare/doctype/therapy_plan_detail/therapy_plan_detail.json deleted file mode 100644 index 77f08af07d9..00000000000 --- a/erpnext/healthcare/doctype/therapy_plan_detail/therapy_plan_detail.json +++ /dev/null @@ -1,49 +0,0 @@ -{ - "actions": [], - "creation": "2020-03-29 20:52:57.068731", - "doctype": "DocType", - "editable_grid": 1, - "engine": "InnoDB", - "field_order": [ - "therapy_type", - "no_of_sessions", - "sessions_completed" - ], - "fields": [ - { - "fieldname": "therapy_type", - "fieldtype": "Link", - "in_list_view": 1, - "label": "Therapy Type", - "options": "Therapy Type", - "reqd": 1 - }, - { - "fieldname": "no_of_sessions", - "fieldtype": "Int", - "in_list_view": 1, - "label": "No of Sessions" - }, - { - "default": "0", - "depends_on": "eval:doc.parenttype=='Therapy Plan';", - "fieldname": "sessions_completed", - "fieldtype": "Int", - "label": "Sessions Completed", - "no_copy": 1, - "read_only": 1 - } - ], - "istable": 1, - "links": [], - "modified": "2020-11-04 18:15:52.173450", - "modified_by": "Administrator", - "module": "Healthcare", - "name": "Therapy Plan Detail", - "owner": "Administrator", - "permissions": [], - "quick_entry": 1, - "sort_field": "modified", - "sort_order": "DESC", - "track_changes": 1 -} \ No newline at end of file diff --git a/erpnext/healthcare/doctype/therapy_plan_detail/therapy_plan_detail.py b/erpnext/healthcare/doctype/therapy_plan_detail/therapy_plan_detail.py deleted file mode 100644 index 1842fc2197b..00000000000 --- a/erpnext/healthcare/doctype/therapy_plan_detail/therapy_plan_detail.py +++ /dev/null @@ -1,12 +0,0 @@ -# -*- coding: utf-8 -*- -# Copyright (c) 2020, Frappe Technologies Pvt. Ltd. and contributors -# For license information, please see license.txt - -from __future__ import unicode_literals - -# import frappe -from frappe.model.document import Document - - -class TherapyPlanDetail(Document): - pass diff --git a/erpnext/healthcare/doctype/therapy_plan_template/__init__.py b/erpnext/healthcare/doctype/therapy_plan_template/__init__.py deleted file mode 100644 index e69de29bb2d..00000000000 diff --git a/erpnext/healthcare/doctype/therapy_plan_template/test_therapy_plan_template.py b/erpnext/healthcare/doctype/therapy_plan_template/test_therapy_plan_template.py deleted file mode 100644 index cd3d5686bc0..00000000000 --- a/erpnext/healthcare/doctype/therapy_plan_template/test_therapy_plan_template.py +++ /dev/null @@ -1,11 +0,0 @@ -# -*- coding: utf-8 -*- -# Copyright (c) 2020, Frappe Technologies Pvt. Ltd. and Contributors -# See license.txt -from __future__ import unicode_literals - -# import frappe -import unittest - - -class TestTherapyPlanTemplate(unittest.TestCase): - pass diff --git a/erpnext/healthcare/doctype/therapy_plan_template/therapy_plan_template.js b/erpnext/healthcare/doctype/therapy_plan_template/therapy_plan_template.js deleted file mode 100644 index 86de1928e23..00000000000 --- a/erpnext/healthcare/doctype/therapy_plan_template/therapy_plan_template.js +++ /dev/null @@ -1,57 +0,0 @@ -// Copyright (c) 2020, Frappe Technologies Pvt. Ltd. and contributors -// For license information, please see license.txt - -frappe.ui.form.on('Therapy Plan Template', { - refresh: function(frm) { - frm.set_query('therapy_type', 'therapy_types', () => { - return { - filters: { - 'is_billable': 1 - } - }; - }); - }, - - set_totals: function(frm) { - let total_sessions = 0; - let total_amount = 0.0; - frm.doc.therapy_types.forEach((d) => { - if (d.no_of_sessions) total_sessions += cint(d.no_of_sessions); - if (d.amount) total_amount += flt(d.amount); - }); - frm.set_value('total_sessions', total_sessions); - frm.set_value('total_amount', total_amount); - frm.refresh_fields(); - } -}); - -frappe.ui.form.on('Therapy Plan Template Detail', { - therapy_type: function(frm, cdt, cdn) { - let row = locals[cdt][cdn]; - frappe.call('frappe.client.get', { - doctype: 'Therapy Type', - name: row.therapy_type - }).then((res) => { - row.rate = res.message.rate; - if (!row.no_of_sessions) - row.no_of_sessions = 1; - row.amount = flt(row.rate) * cint(row.no_of_sessions); - frm.refresh_field('therapy_types'); - frm.trigger('set_totals'); - }); - }, - - no_of_sessions: function(frm, cdt, cdn) { - let row = locals[cdt][cdn]; - row.amount = flt(row.rate) * cint(row.no_of_sessions); - frm.refresh_field('therapy_types'); - frm.trigger('set_totals'); - }, - - rate: function(frm, cdt, cdn) { - let row = locals[cdt][cdn]; - row.amount = flt(row.rate) * cint(row.no_of_sessions); - frm.refresh_field('therapy_types'); - frm.trigger('set_totals'); - } -}); diff --git a/erpnext/healthcare/doctype/therapy_plan_template/therapy_plan_template.json b/erpnext/healthcare/doctype/therapy_plan_template/therapy_plan_template.json deleted file mode 100644 index 48fc896257b..00000000000 --- a/erpnext/healthcare/doctype/therapy_plan_template/therapy_plan_template.json +++ /dev/null @@ -1,132 +0,0 @@ -{ - "actions": [], - "autoname": "field:plan_name", - "creation": "2020-09-22 17:51:38.861055", - "doctype": "DocType", - "editable_grid": 1, - "engine": "InnoDB", - "field_order": [ - "plan_name", - "linked_item_details_section", - "item_code", - "item_name", - "item_group", - "column_break_6", - "description", - "linked_item", - "therapy_types_section", - "therapy_types", - "section_break_11", - "total_sessions", - "column_break_13", - "total_amount" - ], - "fields": [ - { - "fieldname": "plan_name", - "fieldtype": "Data", - "in_list_view": 1, - "label": "Plan Name", - "reqd": 1, - "unique": 1 - }, - { - "fieldname": "therapy_types_section", - "fieldtype": "Section Break", - "label": "Therapy Types" - }, - { - "fieldname": "therapy_types", - "fieldtype": "Table", - "label": "Therapy Types", - "options": "Therapy Plan Template Detail", - "reqd": 1 - }, - { - "fieldname": "linked_item", - "fieldtype": "Link", - "label": "Linked Item", - "options": "Item", - "read_only": 1 - }, - { - "fieldname": "linked_item_details_section", - "fieldtype": "Section Break", - "label": "Linked Item Details" - }, - { - "fieldname": "item_code", - "fieldtype": "Data", - "label": "Item Code", - "reqd": 1, - "set_only_once": 1 - }, - { - "fieldname": "item_name", - "fieldtype": "Data", - "label": "Item Name", - "reqd": 1 - }, - { - "fieldname": "item_group", - "fieldtype": "Link", - "label": "Item Group", - "options": "Item Group", - "reqd": 1 - }, - { - "fieldname": "column_break_6", - "fieldtype": "Column Break" - }, - { - "fieldname": "description", - "fieldtype": "Small Text", - "label": "Item Description" - }, - { - "fieldname": "total_amount", - "fieldtype": "Currency", - "label": "Total Amount", - "read_only": 1 - }, - { - "fieldname": "section_break_11", - "fieldtype": "Section Break" - }, - { - "fieldname": "total_sessions", - "fieldtype": "Int", - "label": "Total Sessions", - "read_only": 1 - }, - { - "fieldname": "column_break_13", - "fieldtype": "Column Break" - } - ], - "index_web_pages_for_search": 1, - "links": [], - "modified": "2020-10-08 00:56:58.062105", - "modified_by": "Administrator", - "module": "Healthcare", - "name": "Therapy Plan Template", - "owner": "Administrator", - "permissions": [ - { - "create": 1, - "delete": 1, - "email": 1, - "export": 1, - "print": 1, - "read": 1, - "report": 1, - "role": "System Manager", - "share": 1, - "write": 1 - } - ], - "quick_entry": 1, - "sort_field": "modified", - "sort_order": "DESC", - "track_changes": 1 -} \ No newline at end of file diff --git a/erpnext/healthcare/doctype/therapy_plan_template/therapy_plan_template.py b/erpnext/healthcare/doctype/therapy_plan_template/therapy_plan_template.py deleted file mode 100644 index f5512be207f..00000000000 --- a/erpnext/healthcare/doctype/therapy_plan_template/therapy_plan_template.py +++ /dev/null @@ -1,76 +0,0 @@ -# -*- coding: utf-8 -*- -# Copyright (c) 2020, Frappe Technologies Pvt. Ltd. and contributors -# For license information, please see license.txt - -from __future__ import unicode_literals - -import frappe -from frappe.model.document import Document -from frappe.utils import cint, flt - -from erpnext.healthcare.doctype.therapy_type.therapy_type import make_item_price - - -class TherapyPlanTemplate(Document): - def after_insert(self): - self.create_item_from_template() - - def validate(self): - self.set_totals() - - def on_update(self): - doc_before_save = self.get_doc_before_save() - if not doc_before_save: return - if doc_before_save.item_name != self.item_name or doc_before_save.item_group != self.item_group \ - or doc_before_save.description != self.description: - self.update_item() - - if doc_before_save.therapy_types != self.therapy_types: - self.update_item_price() - - def set_totals(self): - total_sessions = 0 - total_amount = 0 - - for entry in self.therapy_types: - total_sessions += cint(entry.no_of_sessions) - total_amount += flt(entry.amount) - - self.total_sessions = total_sessions - self.total_amount = total_amount - - def create_item_from_template(self): - uom = frappe.db.exists('UOM', 'Nos') or frappe.db.get_single_value('Stock Settings', 'stock_uom') - - item = frappe.get_doc({ - 'doctype': 'Item', - 'item_code': self.item_code, - 'item_name': self.item_name, - 'item_group': self.item_group, - 'description': self.description, - 'is_sales_item': 1, - 'is_service_item': 1, - 'is_purchase_item': 0, - 'is_stock_item': 0, - 'show_in_website': 0, - 'is_pro_applicable': 0, - 'stock_uom': uom - }).insert(ignore_permissions=True, ignore_mandatory=True) - - make_item_price(item.name, self.total_amount) - self.db_set('linked_item', item.name) - - def update_item(self): - item_doc = frappe.get_doc('Item', {'item_code': self.linked_item}) - item_doc.item_name = self.item_name - item_doc.item_group = self.item_group - item_doc.description = self.description - item_doc.ignore_mandatory = True - item_doc.save(ignore_permissions=True) - - def update_item_price(self): - item_price = frappe.get_doc('Item Price', {'item_code': self.linked_item}) - item_price.item_name = self.item_name - item_price.price_list_rate = self.total_amount - item_price.ignore_mandatory = True - item_price.save(ignore_permissions=True) diff --git a/erpnext/healthcare/doctype/therapy_plan_template/therapy_plan_template_dashboard.py b/erpnext/healthcare/doctype/therapy_plan_template/therapy_plan_template_dashboard.py deleted file mode 100644 index def5c482d15..00000000000 --- a/erpnext/healthcare/doctype/therapy_plan_template/therapy_plan_template_dashboard.py +++ /dev/null @@ -1,15 +0,0 @@ -from __future__ import unicode_literals - -from frappe import _ - - -def get_data(): - return { - 'fieldname': 'therapy_plan_template', - 'transactions': [ - { - 'label': _('Therapy Plans'), - 'items': ['Therapy Plan'] - } - ] - } diff --git a/erpnext/healthcare/doctype/therapy_plan_template_detail/__init__.py b/erpnext/healthcare/doctype/therapy_plan_template_detail/__init__.py deleted file mode 100644 index e69de29bb2d..00000000000 diff --git a/erpnext/healthcare/doctype/therapy_plan_template_detail/therapy_plan_template_detail.json b/erpnext/healthcare/doctype/therapy_plan_template_detail/therapy_plan_template_detail.json deleted file mode 100644 index 5553a118f87..00000000000 --- a/erpnext/healthcare/doctype/therapy_plan_template_detail/therapy_plan_template_detail.json +++ /dev/null @@ -1,54 +0,0 @@ -{ - "actions": [], - "creation": "2020-10-07 23:04:44.373381", - "doctype": "DocType", - "editable_grid": 1, - "engine": "InnoDB", - "field_order": [ - "therapy_type", - "no_of_sessions", - "rate", - "amount" - ], - "fields": [ - { - "fieldname": "therapy_type", - "fieldtype": "Link", - "in_list_view": 1, - "label": "Therapy Type", - "options": "Therapy Type", - "reqd": 1 - }, - { - "fieldname": "no_of_sessions", - "fieldtype": "Int", - "in_list_view": 1, - "label": "No of Sessions" - }, - { - "fieldname": "rate", - "fieldtype": "Currency", - "in_list_view": 1, - "label": "Rate" - }, - { - "fieldname": "amount", - "fieldtype": "Currency", - "in_list_view": 1, - "label": "Amount", - "read_only": 1 - } - ], - "istable": 1, - "links": [], - "modified": "2020-10-07 23:46:54.296322", - "modified_by": "Administrator", - "module": "Healthcare", - "name": "Therapy Plan Template Detail", - "owner": "Administrator", - "permissions": [], - "quick_entry": 1, - "sort_field": "modified", - "sort_order": "DESC", - "track_changes": 1 -} \ No newline at end of file diff --git a/erpnext/healthcare/doctype/therapy_plan_template_detail/therapy_plan_template_detail.py b/erpnext/healthcare/doctype/therapy_plan_template_detail/therapy_plan_template_detail.py deleted file mode 100644 index 104c1bf28bd..00000000000 --- a/erpnext/healthcare/doctype/therapy_plan_template_detail/therapy_plan_template_detail.py +++ /dev/null @@ -1,12 +0,0 @@ -# -*- coding: utf-8 -*- -# Copyright (c) 2020, Frappe Technologies Pvt. Ltd. and contributors -# For license information, please see license.txt - -from __future__ import unicode_literals - -# import frappe -from frappe.model.document import Document - - -class TherapyPlanTemplateDetail(Document): - pass diff --git a/erpnext/healthcare/doctype/therapy_session/__init__.py b/erpnext/healthcare/doctype/therapy_session/__init__.py deleted file mode 100644 index e69de29bb2d..00000000000 diff --git a/erpnext/healthcare/doctype/therapy_session/test_therapy_session.py b/erpnext/healthcare/doctype/therapy_session/test_therapy_session.py deleted file mode 100644 index e4afacf3f0a..00000000000 --- a/erpnext/healthcare/doctype/therapy_session/test_therapy_session.py +++ /dev/null @@ -1,11 +0,0 @@ -# -*- coding: utf-8 -*- -# Copyright (c) 2020, Frappe Technologies Pvt. Ltd. and Contributors -# See license.txt -from __future__ import unicode_literals - -# import frappe -import unittest - - -class TestTherapySession(unittest.TestCase): - pass diff --git a/erpnext/healthcare/doctype/therapy_session/therapy_session.js b/erpnext/healthcare/doctype/therapy_session/therapy_session.js deleted file mode 100644 index fbfa774c91c..00000000000 --- a/erpnext/healthcare/doctype/therapy_session/therapy_session.js +++ /dev/null @@ -1,171 +0,0 @@ -// Copyright (c) 2020, Frappe Technologies Pvt. Ltd. and contributors -// For license information, please see license.txt - -frappe.ui.form.on('Therapy Session', { - setup: function(frm) { - frm.get_field('exercises').grid.editable_fields = [ - {fieldname: 'exercise_type', columns: 7}, - {fieldname: 'counts_target', columns: 1}, - {fieldname: 'counts_completed', columns: 1}, - {fieldname: 'assistance_level', columns: 1} - ]; - - frm.set_query('service_unit', function() { - return { - filters: { - 'is_group': false, - 'allow_appointments': true, - 'company': frm.doc.company - } - }; - }); - - frm.set_query('appointment', function() { - - return { - filters: { - 'status': ['in', ['Open', 'Scheduled']] - } - }; - }); - }, - - refresh: function(frm) { - if (frm.doc.therapy_plan) { - frm.trigger('filter_therapy_types'); - } - - if (!frm.doc.__islocal) { - frm.dashboard.add_indicator(__('Counts Targeted: {0}', [frm.doc.total_counts_targeted]), 'blue'); - frm.dashboard.add_indicator(__('Counts Completed: {0}', [frm.doc.total_counts_completed]), - (frm.doc.total_counts_completed < frm.doc.total_counts_targeted) ? 'orange' : 'green'); - } - - if (frm.doc.docstatus === 1) { - frm.add_custom_button(__('Patient Assessment'), function() { - frappe.model.open_mapped_doc({ - method: 'erpnext.healthcare.doctype.patient_assessment.patient_assessment.create_patient_assessment', - frm: frm, - }) - }, 'Create'); - - frappe.db.get_value('Therapy Plan', {'name': frm.doc.therapy_plan}, 'therapy_plan_template', (r) => { - if (r && !r.therapy_plan_template) { - frm.add_custom_button(__('Sales Invoice'), function() { - frappe.model.open_mapped_doc({ - method: 'erpnext.healthcare.doctype.therapy_session.therapy_session.invoice_therapy_session', - frm: frm, - }); - }, 'Create'); - } - }); - } - }, - - therapy_plan: function(frm) { - if (frm.doc.therapy_plan) { - frm.trigger('filter_therapy_types'); - } - }, - - filter_therapy_types: function(frm) { - frappe.call({ - 'method': 'frappe.client.get', - args: { - doctype: 'Therapy Plan', - name: frm.doc.therapy_plan - }, - callback: function(data) { - let therapy_types = (data.message.therapy_plan_details || []).map(function(d){ return d.therapy_type; }); - frm.set_query('therapy_type', function() { - return { - filters: { 'therapy_type': ['in', therapy_types]} - }; - }); - } - }); - }, - - patient: function(frm) { - if (frm.doc.patient) { - frappe.call({ - 'method': 'erpnext.healthcare.doctype.patient.patient.get_patient_detail', - args: { - patient: frm.doc.patient - }, - callback: function (data) { - let age = ''; - if (data.message.dob) { - age = calculate_age(data.message.dob); - } else if (data.message.age) { - age = data.message.age; - if (data.message.age_as_on) { - age = __('{0} as on {1}', [age, data.message.age_as_on]); - } - } - frm.set_value('patient_age', age); - frm.set_value('gender', data.message.sex); - frm.set_value('patient_name', data.message.patient_name); - } - }); - } else { - frm.set_value('patient_age', ''); - frm.set_value('gender', ''); - frm.set_value('patient_name', ''); - } - }, - - appointment: function(frm) { - if (frm.doc.appointment) { - frappe.call({ - 'method': 'frappe.client.get', - args: { - doctype: 'Patient Appointment', - name: frm.doc.appointment - }, - callback: function(data) { - let values = { - 'patient':data.message.patient, - 'therapy_type': data.message.therapy_type, - 'therapy_plan': data.message.therapy_plan, - 'practitioner': data.message.practitioner, - 'department': data.message.department, - 'start_date': data.message.appointment_date, - 'start_time': data.message.appointment_time, - 'service_unit': data.message.service_unit, - 'company': data.message.company, - 'duration': data.message.duration - }; - frm.set_value(values); - } - }); - } - }, - - therapy_type: function(frm) { - if (frm.doc.therapy_type) { - frappe.call({ - 'method': 'frappe.client.get', - args: { - doctype: 'Therapy Type', - name: frm.doc.therapy_type - }, - callback: function(data) { - frm.set_value('duration', data.message.default_duration); - frm.set_value('rate', data.message.rate); - frm.set_value('service_unit', data.message.healthcare_service_unit); - frm.set_value('department', data.message.medical_department); - frm.doc.exercises = []; - $.each(data.message.exercises, function(_i, e) { - let exercise = frm.add_child('exercises'); - exercise.exercise_type = e.exercise_type; - exercise.difficulty_level = e.difficulty_level; - exercise.counts_target = e.counts_target; - exercise.assistance_level = e.assistance_level; - }); - refresh_field('exercises'); - } - }); - } - } -}); diff --git a/erpnext/healthcare/doctype/therapy_session/therapy_session.json b/erpnext/healthcare/doctype/therapy_session/therapy_session.json deleted file mode 100644 index 0bb2b0ef2ae..00000000000 --- a/erpnext/healthcare/doctype/therapy_session/therapy_session.json +++ /dev/null @@ -1,264 +0,0 @@ -{ - "actions": [], - "autoname": "naming_series:", - "creation": "2020-03-11 08:57:40.669857", - "doctype": "DocType", - "editable_grid": 1, - "engine": "InnoDB", - "field_order": [ - "naming_series", - "appointment", - "patient", - "patient_name", - "patient_age", - "gender", - "column_break_5", - "company", - "therapy_plan", - "therapy_type", - "practitioner", - "department", - "details_section", - "medical_code", - "duration", - "rate", - "location", - "column_break_12", - "service_unit", - "start_date", - "start_time", - "invoiced", - "exercises_section", - "exercises", - "section_break_23", - "total_counts_targeted", - "column_break_25", - "total_counts_completed", - "amended_from" - ], - "fields": [ - { - "fieldname": "naming_series", - "fieldtype": "Select", - "label": "Series", - "options": "HLC-THP-.YYYY.-" - }, - { - "fieldname": "appointment", - "fieldtype": "Link", - "label": "Appointment", - "options": "Patient Appointment", - "set_only_once": 1 - }, - { - "fieldname": "patient", - "fieldtype": "Link", - "in_list_view": 1, - "label": "Patient", - "options": "Patient", - "reqd": 1 - }, - { - "fetch_from": "patient.sex", - "fieldname": "gender", - "fieldtype": "Link", - "label": "Gender", - "options": "Gender", - "read_only": 1 - }, - { - "fieldname": "column_break_5", - "fieldtype": "Column Break" - }, - { - "fieldname": "practitioner", - "fieldtype": "Link", - "label": "Healthcare Practitioner", - "options": "Healthcare Practitioner" - }, - { - "fieldname": "department", - "fieldtype": "Link", - "label": "Medical Department", - "options": "Medical Department" - }, - { - "fieldname": "details_section", - "fieldtype": "Section Break", - "label": "Details" - }, - { - "fetch_from": "therapy_template.default_duration", - "fieldname": "duration", - "fieldtype": "Int", - "label": "Duration", - "reqd": 1 - }, - { - "fieldname": "location", - "fieldtype": "Select", - "label": "Location", - "options": "\nCenter\nHome\nTele" - }, - { - "fieldname": "column_break_12", - "fieldtype": "Column Break" - }, - { - "fetch_from": "therapy_template.rate", - "fieldname": "rate", - "fieldtype": "Currency", - "label": "Rate" - }, - { - "fieldname": "exercises_section", - "fieldtype": "Section Break", - "label": "Exercises" - }, - { - "fieldname": "exercises", - "fieldtype": "Table", - "label": "Exercises", - "options": "Exercise" - }, - { - "depends_on": "eval: doc.therapy_plan", - "fieldname": "therapy_type", - "fieldtype": "Link", - "in_list_view": 1, - "label": "Therapy Type", - "options": "Therapy Type", - "reqd": 1 - }, - { - "fieldname": "therapy_plan", - "fieldtype": "Link", - "label": "Therapy Plan", - "options": "Therapy Plan", - "reqd": 1, - "set_only_once": 1 - }, - { - "fieldname": "amended_from", - "fieldtype": "Link", - "label": "Amended From", - "no_copy": 1, - "options": "Therapy Session", - "print_hide": 1, - "read_only": 1 - }, - { - "fieldname": "service_unit", - "fieldtype": "Link", - "label": "Healthcare Service Unit", - "options": "Healthcare Service Unit" - }, - { - "fieldname": "start_date", - "fieldtype": "Date", - "label": "Start Date", - "reqd": 1 - }, - { - "fieldname": "start_time", - "fieldtype": "Time", - "label": "Start Time" - }, - { - "fieldname": "company", - "fieldtype": "Link", - "label": "Company", - "options": "Company", - "reqd": 1 - }, - { - "default": "0", - "fieldname": "invoiced", - "fieldtype": "Check", - "label": "Invoiced", - "read_only": 1 - }, - { - "fieldname": "patient_age", - "fieldtype": "Data", - "label": "Patient Age", - "read_only": 1 - }, - { - "fieldname": "total_counts_targeted", - "fieldtype": "Int", - "label": "Total Counts Targeted", - "read_only": 1 - }, - { - "fieldname": "total_counts_completed", - "fieldtype": "Int", - "label": "Total Counts Completed", - "no_copy": 1, - "read_only": 1 - }, - { - "fieldname": "section_break_23", - "fieldtype": "Section Break" - }, - { - "fieldname": "column_break_25", - "fieldtype": "Column Break" - }, - { - "fetch_from": "patient.patient_name", - "fieldname": "patient_name", - "fieldtype": "Data", - "label": "Patient Name", - "read_only": 1 - }, - { - "fetch_from": "therapy_type.medical_code", - "fieldname": "medical_code", - "fieldtype": "Link", - "label": "Medical Code", - "options": "Medical Code", - "read_only": 1 - } - ], - "is_submittable": 1, - "links": [], - "modified": "2020-11-04 18:14:25.999939", - "modified_by": "Administrator", - "module": "Healthcare", - "name": "Therapy Session", - "owner": "Administrator", - "permissions": [ - { - "create": 1, - "delete": 1, - "email": 1, - "export": 1, - "print": 1, - "read": 1, - "report": 1, - "role": "System Manager", - "share": 1, - "write": 1 - }, - { - "cancel": 1, - "create": 1, - "email": 1, - "export": 1, - "print": 1, - "read": 1, - "report": 1, - "role": "Physician", - "share": 1, - "submit": 1, - "write": 1 - } - ], - "quick_entry": 1, - "search_fields": "patient,appointment,therapy_plan,therapy_type", - "sort_field": "modified", - "sort_order": "DESC", - "title_field": "patient", - "track_changes": 1 -} \ No newline at end of file diff --git a/erpnext/healthcare/doctype/therapy_session/therapy_session.py b/erpnext/healthcare/doctype/therapy_session/therapy_session.py deleted file mode 100644 index 915e6e42f4c..00000000000 --- a/erpnext/healthcare/doctype/therapy_session/therapy_session.py +++ /dev/null @@ -1,149 +0,0 @@ -# -*- coding: utf-8 -*- -# Copyright (c) 2020, Frappe Technologies Pvt. Ltd. and contributors -# For license information, please see license.txt - -from __future__ import unicode_literals - -import datetime - -import frappe -from frappe import _ -from frappe.model.document import Document -from frappe.model.mapper import get_mapped_doc -from frappe.utils import flt, get_link_to_form, get_time, getdate - -from erpnext.healthcare.doctype.healthcare_settings.healthcare_settings import ( - get_income_account, - get_receivable_account, -) - - -class TherapySession(Document): - def validate(self): - self.validate_duplicate() - self.set_total_counts() - - def validate_duplicate(self): - end_time = datetime.datetime.combine(getdate(self.start_date), get_time(self.start_time)) \ - + datetime.timedelta(minutes=flt(self.duration)) - - overlaps = frappe.db.sql(""" - select - name - from - `tabTherapy Session` - where - start_date=%s and name!=%s and docstatus!=2 - and (practitioner=%s or patient=%s) and - ((start_time<%s and start_time + INTERVAL duration MINUTE>%s) or - (start_time>%s and start_time<%s) or - (start_time=%s)) - """, (self.start_date, self.name, self.practitioner, self.patient, - self.start_time, end_time.time(), self.start_time, end_time.time(), self.start_time)) - - if overlaps: - overlapping_details = _('Therapy Session overlaps with {0}').format(get_link_to_form('Therapy Session', overlaps[0][0])) - frappe.throw(overlapping_details, title=_('Therapy Sessions Overlapping')) - - def on_submit(self): - self.update_sessions_count_in_therapy_plan() - - def on_update(self): - if self.appointment: - frappe.db.set_value('Patient Appointment', self.appointment, 'status', 'Closed') - - def on_cancel(self): - if self.appointment: - frappe.db.set_value('Patient Appointment', self.appointment, 'status', 'Open') - - self.update_sessions_count_in_therapy_plan(on_cancel=True) - - def update_sessions_count_in_therapy_plan(self, on_cancel=False): - therapy_plan = frappe.get_doc('Therapy Plan', self.therapy_plan) - for entry in therapy_plan.therapy_plan_details: - if entry.therapy_type == self.therapy_type: - if on_cancel: - entry.sessions_completed -= 1 - else: - entry.sessions_completed += 1 - therapy_plan.save() - - def set_total_counts(self): - target_total = 0 - counts_completed = 0 - for entry in self.exercises: - if entry.counts_target: - target_total += entry.counts_target - if entry.counts_completed: - counts_completed += entry.counts_completed - - self.db_set('total_counts_targeted', target_total) - self.db_set('total_counts_completed', counts_completed) - - -@frappe.whitelist() -def create_therapy_session(source_name, target_doc=None): - def set_missing_values(source, target): - therapy_type = frappe.get_doc('Therapy Type', source.therapy_type) - target.exercises = therapy_type.exercises - - doc = get_mapped_doc('Patient Appointment', source_name, { - 'Patient Appointment': { - 'doctype': 'Therapy Session', - 'field_map': [ - ['appointment', 'name'], - ['patient', 'patient'], - ['patient_age', 'patient_age'], - ['gender', 'patient_sex'], - ['therapy_type', 'therapy_type'], - ['therapy_plan', 'therapy_plan'], - ['practitioner', 'practitioner'], - ['department', 'department'], - ['start_date', 'appointment_date'], - ['start_time', 'appointment_time'], - ['service_unit', 'service_unit'], - ['company', 'company'], - ['invoiced', 'invoiced'] - ] - } - }, target_doc, set_missing_values) - - return doc - - -@frappe.whitelist() -def invoice_therapy_session(source_name, target_doc=None): - def set_missing_values(source, target): - target.customer = frappe.db.get_value('Patient', source.patient, 'customer') - target.due_date = getdate() - target.debit_to = get_receivable_account(source.company) - item = target.append('items', {}) - item = get_therapy_item(source, item) - target.set_missing_values(for_validate=True) - - doc = get_mapped_doc('Therapy Session', source_name, { - 'Therapy Session': { - 'doctype': 'Sales Invoice', - 'field_map': [ - ['patient', 'patient'], - ['referring_practitioner', 'practitioner'], - ['company', 'company'], - ['due_date', 'start_date'] - ] - } - }, target_doc, set_missing_values) - - return doc - - -def get_therapy_item(therapy, item): - item.item_code = frappe.db.get_value('Therapy Type', therapy.therapy_type, 'item') - item.description = _('Therapy Session Charges: {0}').format(therapy.practitioner) - item.income_account = get_income_account(therapy.practitioner, therapy.company) - item.cost_center = frappe.get_cached_value('Company', therapy.company, 'cost_center') - item.rate = therapy.rate - item.amount = therapy.rate - item.qty = 1 - item.reference_dt = 'Therapy Session' - item.reference_dn = therapy.name - return item diff --git a/erpnext/healthcare/doctype/therapy_session/therapy_session_dashboard.py b/erpnext/healthcare/doctype/therapy_session/therapy_session_dashboard.py deleted file mode 100644 index b8a37820ba0..00000000000 --- a/erpnext/healthcare/doctype/therapy_session/therapy_session_dashboard.py +++ /dev/null @@ -1,15 +0,0 @@ -from __future__ import unicode_literals - -from frappe import _ - - -def get_data(): - return { - 'fieldname': 'therapy_session', - 'transactions': [ - { - 'label': _('Assessments'), - 'items': ['Patient Assessment'] - } - ] - } diff --git a/erpnext/healthcare/doctype/therapy_type/__init__.py b/erpnext/healthcare/doctype/therapy_type/__init__.py deleted file mode 100644 index e69de29bb2d..00000000000 diff --git a/erpnext/healthcare/doctype/therapy_type/test_therapy_type.py b/erpnext/healthcare/doctype/therapy_type/test_therapy_type.py deleted file mode 100644 index 23d542236b8..00000000000 --- a/erpnext/healthcare/doctype/therapy_type/test_therapy_type.py +++ /dev/null @@ -1,56 +0,0 @@ -# -*- coding: utf-8 -*- -# Copyright (c) 2020, Frappe Technologies Pvt. Ltd. and Contributors -# See license.txt -from __future__ import unicode_literals - -import unittest - -import frappe - - -class TestTherapyType(unittest.TestCase): - def test_therapy_type_item(self): - therapy_type = create_therapy_type() - self.assertTrue(frappe.db.exists('Item', therapy_type.item)) - - therapy_type.disabled = 1 - therapy_type.save() - self.assertEqual(frappe.db.get_value('Item', therapy_type.item, 'disabled'), 1) - -def create_therapy_type(): - exercise = create_exercise_type() - therapy_type = frappe.db.exists('Therapy Type', 'Basic Rehab') - if not therapy_type: - therapy_type = frappe.new_doc('Therapy Type') - therapy_type.therapy_type = 'Basic Rehab' - therapy_type.default_duration = 30 - therapy_type.is_billable = 1 - therapy_type.rate = 5000 - therapy_type.item_code = 'Basic Rehab' - therapy_type.item_name = 'Basic Rehab' - therapy_type.item_group = 'Services' - therapy_type.append('exercises', { - 'exercise_type': exercise.name, - 'counts_target': 10, - 'assistance_level': 'Passive' - }) - therapy_type.save() - else: - therapy_type = frappe.get_doc('Therapy Type', therapy_type) - - return therapy_type - -def create_exercise_type(): - exercise_type = frappe.db.exists('Exercise Type', 'Sit to Stand') - if not exercise_type: - exercise_type = frappe.new_doc('Exercise Type') - exercise_type.exercise_name = 'Sit to Stand' - exercise_type.append('steps_table', { - 'title': 'Step 1', - 'description': 'Squat and Rise' - }) - exercise_type.save() - else: - exercise_type = frappe.get_doc('Exercise Type', exercise_type) - - return exercise_type diff --git a/erpnext/healthcare/doctype/therapy_type/therapy_type.js b/erpnext/healthcare/doctype/therapy_type/therapy_type.js deleted file mode 100644 index 6e155dc21f9..00000000000 --- a/erpnext/healthcare/doctype/therapy_type/therapy_type.js +++ /dev/null @@ -1,103 +0,0 @@ -// Copyright (c) 2020, Frappe Technologies Pvt. Ltd. and contributors -// For license information, please see license.txt - -frappe.ui.form.on('Therapy Type', { - setup: function(frm) { - frm.get_field('exercises').grid.editable_fields = [ - {fieldname: 'exercise_type', columns: 7}, - {fieldname: 'difficulty_level', columns: 1}, - {fieldname: 'counts_target', columns: 1}, - {fieldname: 'assistance_level', columns: 1} - ]; - }, - - refresh: function(frm) { - if (!frm.doc.__islocal) { - cur_frm.add_custom_button(__('Change Item Code'), function() { - change_template_code(frm.doc); - }); - } - }, - - therapy_type: function(frm) { - if (!frm.doc.item_code) - frm.set_value('item_code', frm.doc.therapy_type); - if (!frm.doc.description) - frm.set_value('description', frm.doc.therapy_type); - mark_change_in_item(frm); - }, - - rate: function(frm) { - mark_change_in_item(frm); - }, - - is_billable: function (frm) { - mark_change_in_item(frm); - }, - - item_group: function(frm) { - mark_change_in_item(frm); - }, - - description: function(frm) { - mark_change_in_item(frm); - }, - - medical_department: function(frm) { - mark_change_in_item(frm); - }, - - medical_code: function(frm) { - frm.set_query("medical_code", function() { - return { - filters: { - medical_code_standard: frm.doc.medical_code_standard - } - }; - }); - } -}); - -let mark_change_in_item = function(frm) { - if (!frm.doc.__islocal) { - frm.doc.change_in_item = 1; - } -}; - -let change_template_code = function(doc) { - let d = new frappe.ui.Dialog({ - title:__('Change Item Code'), - fields:[ - { - 'fieldtype': 'Data', - 'label': 'Item Code', - 'fieldname': 'item_code', - reqd: 1 - } - ], - primary_action: function() { - let values = d.get_values(); - - if (values) { - frappe.call({ - 'method': 'erpnext.healthcare.doctype.therapy_type.therapy_type.change_item_code_from_therapy', - 'args': {item_code: values.item_code, doc: doc}, - callback: function () { - cur_frm.reload_doc(); - frappe.show_alert({ - message: 'Item Code renamed successfully', - indicator: 'green' - }); - } - }); - } - d.hide(); - }, - primary_action_label: __('Change Item Code') - }); - d.show(); - - d.set_values({ - 'item_code': doc.item_code - }); -}; diff --git a/erpnext/healthcare/doctype/therapy_type/therapy_type.json b/erpnext/healthcare/doctype/therapy_type/therapy_type.json deleted file mode 100644 index f365b1df032..00000000000 --- a/erpnext/healthcare/doctype/therapy_type/therapy_type.json +++ /dev/null @@ -1,234 +0,0 @@ -{ - "actions": [], - "autoname": "field:therapy_type", - "creation": "2020-03-29 20:48:31.715063", - "doctype": "DocType", - "editable_grid": 1, - "engine": "InnoDB", - "field_order": [ - "disabled", - "section_break_2", - "therapy_type", - "default_duration", - "medical_department", - "column_break_3", - "is_billable", - "rate", - "healthcare_service_unit", - "item_details_section", - "item", - "item_code", - "item_name", - "item_group", - "column_break_12", - "description", - "medical_coding_section", - "medical_code_standard", - "medical_code", - "section_break_18", - "therapy_for", - "add_exercises", - "section_break_6", - "exercises", - "change_in_item" - ], - "fields": [ - { - "fieldname": "therapy_type", - "fieldtype": "Data", - "in_list_view": 1, - "label": "Therapy Type", - "reqd": 1, - "unique": 1 - }, - { - "fieldname": "column_break_3", - "fieldtype": "Column Break" - }, - { - "default": "0", - "fieldname": "is_billable", - "fieldtype": "Check", - "label": "Is Billable" - }, - { - "depends_on": "eval:doc.is_billable;", - "fieldname": "rate", - "fieldtype": "Currency", - "label": "Rate", - "mandatory_depends_on": "eval:doc.is_billable;" - }, - { - "fieldname": "section_break_6", - "fieldtype": "Section Break", - "label": "Exercises" - }, - { - "fieldname": "exercises", - "fieldtype": "Table", - "label": "Exercises", - "options": "Exercise" - }, - { - "fieldname": "default_duration", - "fieldtype": "Int", - "label": "Default Duration (In Minutes)" - }, - { - "default": "0", - "fieldname": "disabled", - "fieldtype": "Check", - "label": "Disabled" - }, - { - "fieldname": "item_details_section", - "fieldtype": "Section Break", - "label": "Item Details" - }, - { - "fieldname": "item", - "fieldtype": "Link", - "label": "Item", - "options": "Item", - "read_only": 1 - }, - { - "fieldname": "item_code", - "fieldtype": "Data", - "label": "Item Code", - "reqd": 1, - "set_only_once": 1 - }, - { - "fieldname": "item_group", - "fieldtype": "Link", - "label": "Item Group", - "options": "Item Group", - "reqd": 1 - }, - { - "fieldname": "item_name", - "fieldtype": "Data", - "label": "Item Name", - "reqd": 1 - }, - { - "fieldname": "column_break_12", - "fieldtype": "Column Break" - }, - { - "fieldname": "description", - "fieldtype": "Small Text", - "label": "Description" - }, - { - "fieldname": "section_break_2", - "fieldtype": "Section Break" - }, - { - "fieldname": "medical_department", - "fieldtype": "Link", - "label": "Medical Department", - "options": "Medical Department" - }, - { - "default": "0", - "fieldname": "change_in_item", - "fieldtype": "Check", - "hidden": 1, - "label": "Change In Item", - "print_hide": 1, - "read_only": 1, - "report_hide": 1 - }, - { - "fieldname": "therapy_for", - "fieldtype": "Table MultiSelect", - "label": "Therapy For", - "options": "Body Part Link" - }, - { - "fieldname": "healthcare_service_unit", - "fieldtype": "Link", - "label": "Healthcare Service Unit", - "options": "Healthcare Service Unit" - }, - { - "depends_on": "eval: doc.therapy_for", - "fieldname": "add_exercises", - "fieldtype": "Button", - "label": "Add Exercises", - "options": "add_exercises" - }, - { - "fieldname": "section_break_18", - "fieldtype": "Section Break" - }, - { - "collapsible": 1, - "fieldname": "medical_coding_section", - "fieldtype": "Section Break", - "label": "Medical Coding", - "options": "Medical Coding" - }, - { - "fieldname": "medical_code_standard", - "fieldtype": "Link", - "label": "Medical Code Standard", - "options": "Medical Code Standard" - }, - { - "depends_on": "medical_code_standard", - "fieldname": "medical_code", - "fieldtype": "Link", - "label": "Medical Code", - "options": "Medical Code" - } - ], - "links": [], - "modified": "2020-06-29 14:18:50.669951", - "modified_by": "Administrator", - "module": "Healthcare", - "name": "Therapy Type", - "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": "Healthcare Administrator", - "share": 1, - "write": 1 - }, - { - "email": 1, - "export": 1, - "print": 1, - "read": 1, - "report": 1, - "role": "Physician", - "share": 1, - "write": 1 - } - ], - "quick_entry": 1, - "sort_field": "modified", - "sort_order": "DESC", - "track_changes": 1 -} \ No newline at end of file diff --git a/erpnext/healthcare/doctype/therapy_type/therapy_type.py b/erpnext/healthcare/doctype/therapy_type/therapy_type.py deleted file mode 100644 index 3517ef2c5ad..00000000000 --- a/erpnext/healthcare/doctype/therapy_type/therapy_type.py +++ /dev/null @@ -1,126 +0,0 @@ -# -*- coding: utf-8 -*- -# Copyright (c) 2020, Frappe Technologies Pvt. Ltd. and contributors -# For license information, please see license.txt - -from __future__ import unicode_literals - -import json - -import frappe -from frappe import _ -from frappe.model.document import Document -from frappe.model.rename_doc import rename_doc -from frappe.utils import cint - - -class TherapyType(Document): - def validate(self): - self.enable_disable_item() - - def after_insert(self): - create_item_from_therapy(self) - - def on_update(self): - if self.change_in_item: - self.update_item_and_item_price() - - def enable_disable_item(self): - if self.is_billable: - if self.disabled: - frappe.db.set_value('Item', self.item, 'disabled', 1) - else: - frappe.db.set_value('Item', self.item, 'disabled', 0) - - def update_item_and_item_price(self): - if self.is_billable and self.item: - item_doc = frappe.get_doc('Item', {'item_code': self.item}) - item_doc.item_name = self.item_name - item_doc.item_group = self.item_group - item_doc.description = self.description - item_doc.disabled = 0 - item_doc.ignore_mandatory = True - item_doc.save(ignore_permissions=True) - - if self.rate: - item_price = frappe.get_doc('Item Price', {'item_code': self.item}) - item_price.item_name = self.item_name - item_price.price_list_rate = self.rate - item_price.ignore_mandatory = True - item_price.save() - - elif not self.is_billable and self.item: - frappe.db.set_value('Item', self.item, 'disabled', 1) - - self.db_set('change_in_item', 0) - - @frappe.whitelist() - def add_exercises(self): - exercises = self.get_exercises_for_body_parts() - last_idx = max([cint(d.idx) for d in self.get('exercises')] or [0,]) - for i, d in enumerate(exercises): - ch = self.append('exercises', {}) - ch.exercise_type = d.parent - ch.idx = last_idx + i + 1 - - def get_exercises_for_body_parts(self): - body_parts = [entry.body_part for entry in self.therapy_for] - - exercises = frappe.db.sql( - """ - SELECT DISTINCT - b.parent, e.name, e.difficulty_level - FROM - `tabExercise Type` e, `tabBody Part Link` b - WHERE - b.body_part IN %(body_parts)s AND b.parent=e.name - """, {'body_parts': body_parts}, as_dict=1) - - return exercises - - -def create_item_from_therapy(doc): - disabled = doc.disabled - if doc.is_billable and not doc.disabled: - disabled = 0 - - uom = frappe.db.exists('UOM', 'Unit') or frappe.db.get_single_value('Stock Settings', 'stock_uom') - - item = frappe.get_doc({ - 'doctype': 'Item', - 'item_code': doc.item_code, - 'item_name': doc.item_name, - 'item_group': doc.item_group, - 'description': doc.description, - 'is_sales_item': 1, - 'is_service_item': 1, - 'is_purchase_item': 0, - 'is_stock_item': 0, - 'show_in_website': 0, - 'is_pro_applicable': 0, - 'disabled': disabled, - 'stock_uom': uom - }).insert(ignore_permissions=True, ignore_mandatory=True) - - make_item_price(item.name, doc.rate) - doc.db_set('item', item.name) - - -def make_item_price(item, item_price): - price_list_name = frappe.db.get_value('Price List', {'selling': 1}) - frappe.get_doc({ - 'doctype': 'Item Price', - 'price_list': price_list_name, - 'item_code': item, - 'price_list_rate': item_price - }).insert(ignore_permissions=True, ignore_mandatory=True) - -@frappe.whitelist() -def change_item_code_from_therapy(item_code, doc): - doc = frappe._dict(json.loads(doc)) - - if frappe.db.exists('Item', {'item_code': item_code}): - frappe.throw(_('Item with Item Code {0} already exists').format(item_code)) - else: - rename_doc('Item', doc.item, item_code, ignore_permissions=True) - frappe.db.set_value('Therapy Type', doc.name, 'item_code', item_code) - return diff --git a/erpnext/healthcare/doctype/treatment_plan_template/__init__.py b/erpnext/healthcare/doctype/treatment_plan_template/__init__.py deleted file mode 100644 index e69de29bb2d..00000000000 diff --git a/erpnext/healthcare/doctype/treatment_plan_template/test_records.json b/erpnext/healthcare/doctype/treatment_plan_template/test_records.json deleted file mode 100644 index d661b4304f6..00000000000 --- a/erpnext/healthcare/doctype/treatment_plan_template/test_records.json +++ /dev/null @@ -1,7 +0,0 @@ -[ - { - "doctype": "Treatment Plan Template", - "template_name": "Chemo", - "patient_age_from": 21 - } -] diff --git a/erpnext/healthcare/doctype/treatment_plan_template/treatment_plan_template.js b/erpnext/healthcare/doctype/treatment_plan_template/treatment_plan_template.js deleted file mode 100644 index 986c3cb6e42..00000000000 --- a/erpnext/healthcare/doctype/treatment_plan_template/treatment_plan_template.js +++ /dev/null @@ -1,14 +0,0 @@ -// Copyright (c) 2021, Frappe Technologies Pvt. Ltd. and contributors -// For license information, please see license.txt - -frappe.ui.form.on('Treatment Plan Template', { - refresh: function (frm) { - frm.set_query('type', 'items', function () { - return { - filters: { - 'name': ['in', ['Lab Test Template', 'Clinical Procedure Template', 'Therapy Type']], - } - }; - }); - }, -}); diff --git a/erpnext/healthcare/doctype/treatment_plan_template/treatment_plan_template.json b/erpnext/healthcare/doctype/treatment_plan_template/treatment_plan_template.json deleted file mode 100644 index 85a312fb174..00000000000 --- a/erpnext/healthcare/doctype/treatment_plan_template/treatment_plan_template.json +++ /dev/null @@ -1,189 +0,0 @@ -{ - "actions": [], - "autoname": "field:template_name", - "creation": "2021-06-10 10:14:17.901273", - "doctype": "DocType", - "editable_grid": 1, - "engine": "InnoDB", - "field_order": [ - "section_break_1", - "template_name", - "description", - "practitioners", - "disabled", - "column_break_1", - "medical_department", - "goal", - "order_group", - "section_break_8", - "patient_age_from", - "complaints", - "gender", - "column_break_12", - "patient_age_to", - "diagnosis", - "plan_items_section", - "items", - "drugs" - ], - "fields": [ - { - "fieldname": "section_break_1", - "fieldtype": "Section Break", - "label": "Plan Details" - }, - { - "fieldname": "medical_department", - "fieldtype": "Link", - "in_list_view": 1, - "label": "Medical Department", - "options": "Medical Department" - }, - { - "fieldname": "description", - "fieldtype": "Small Text", - "label": "Description" - }, - { - "fieldname": "goal", - "fieldtype": "Small Text", - "label": "Goal" - }, - { - "fieldname": "practitioners", - "fieldtype": "Table MultiSelect", - "label": "Practitioners", - "options": "Treatment Plan Template Practitioner" - }, - { - "fieldname": "order_group", - "fieldtype": "Link", - "label": "Order Group", - "options": "Patient Encounter", - "read_only": 1 - }, - { - "fieldname": "section_break_8", - "fieldtype": "Section Break", - "label": "Plan Conditions" - }, - { - "fieldname": "template_name", - "fieldtype": "Data", - "in_list_view": 1, - "label": "Template Name", - "reqd": 1, - "unique": 1 - }, - { - "fieldname": "patient_age_from", - "fieldtype": "Int", - "label": "Patient Age From", - "non_negative": 1 - }, - { - "fieldname": "column_break_12", - "fieldtype": "Column Break" - }, - { - "fieldname": "patient_age_to", - "fieldtype": "Int", - "label": "Patient Age To", - "non_negative": 1 - }, - { - "fieldname": "gender", - "fieldtype": "Link", - "label": "Gender", - "options": "Gender" - }, - { - "fieldname": "complaints", - "fieldtype": "Table MultiSelect", - "label": "Complaints", - "options": "Patient Encounter Symptom" - }, - { - "fieldname": "diagnosis", - "fieldtype": "Table MultiSelect", - "label": "Diagnosis", - "options": "Patient Encounter Diagnosis" - }, - { - "fieldname": "plan_items_section", - "fieldtype": "Section Break", - "label": "Plan Items" - }, - { - "fieldname": "items", - "fieldtype": "Table", - "label": "Items", - "options": "Treatment Plan Template Item" - }, - { - "fieldname": "drugs", - "fieldtype": "Table", - "label": "Drugs", - "options": "Drug Prescription" - }, - { - "default": "0", - "fieldname": "disabled", - "fieldtype": "Check", - "label": "Disabled" - }, - { - "fieldname": "column_break_1", - "fieldtype": "Column Break" - } - ], - "index_web_pages_for_search": 1, - "links": [], - "modified": "2021-08-18 02:41:58.354296", - "modified_by": "Administrator", - "module": "Healthcare", - "name": "Treatment Plan Template", - "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": "Physician", - "share": 1, - "write": 1 - }, - { - "create": 1, - "delete": 1, - "email": 1, - "export": 1, - "print": 1, - "read": 1, - "report": 1, - "role": "Healthcare Administrator", - "share": 1, - "write": 1 - } - ], - "sort_field": "modified", - "sort_order": "DESC", - "title_field": "template_name", - "track_changes": 1 -} \ No newline at end of file diff --git a/erpnext/healthcare/doctype/treatment_plan_template/treatment_plan_template.py b/erpnext/healthcare/doctype/treatment_plan_template/treatment_plan_template.py deleted file mode 100644 index dbe0e9ae5f4..00000000000 --- a/erpnext/healthcare/doctype/treatment_plan_template/treatment_plan_template.py +++ /dev/null @@ -1,20 +0,0 @@ -# Copyright (c) 2021, Frappe Technologies Pvt. Ltd. and contributors -# For license information, please see license.txt - -import frappe -from frappe import _ -from frappe.model.document import Document - - -class TreatmentPlanTemplate(Document): - def validate(self): - self.validate_age() - - def validate_age(self): - if self.patient_age_from and self.patient_age_from < 0: - frappe.throw(_('Patient Age From cannot be less than 0')) - if self.patient_age_to and self.patient_age_to < 0: - frappe.throw(_('Patient Age To cannot be less than 0')) - if self.patient_age_to and self.patient_age_from and \ - self.patient_age_to < self.patient_age_from: - frappe.throw(_('Patient Age To cannot be less than Patient Age From')) diff --git a/erpnext/healthcare/doctype/treatment_plan_template/treatment_plan_template_list.js b/erpnext/healthcare/doctype/treatment_plan_template/treatment_plan_template_list.js deleted file mode 100644 index 7ab31dff791..00000000000 --- a/erpnext/healthcare/doctype/treatment_plan_template/treatment_plan_template_list.js +++ /dev/null @@ -1,10 +0,0 @@ -frappe.listview_settings['Treatment Plan Template'] = { - get_indicator: function(doc) { - var colors = { - 1: 'gray', - 0: 'blue', - }; - let label = doc.disabled == 1 ? 'Disabled' : 'Enabled'; - return [__(label), colors[doc.disabled], 'disable,=,' + doc.disabled]; - } -}; diff --git a/erpnext/healthcare/doctype/treatment_plan_template_item/__init__.py b/erpnext/healthcare/doctype/treatment_plan_template_item/__init__.py deleted file mode 100644 index e69de29bb2d..00000000000 diff --git a/erpnext/healthcare/doctype/treatment_plan_template_item/treatment_plan_template_item.json b/erpnext/healthcare/doctype/treatment_plan_template_item/treatment_plan_template_item.json deleted file mode 100644 index 20a9d6793a5..00000000000 --- a/erpnext/healthcare/doctype/treatment_plan_template_item/treatment_plan_template_item.json +++ /dev/null @@ -1,55 +0,0 @@ -{ - "actions": [], - "creation": "2021-06-10 11:47:29.194795", - "doctype": "DocType", - "editable_grid": 1, - "engine": "InnoDB", - "field_order": [ - "type", - "template", - "qty", - "instructions" - ], - "fields": [ - { - "fieldname": "type", - "fieldtype": "Link", - "in_list_view": 1, - "label": "Type", - "options": "DocType", - "reqd": 1 - }, - { - "fieldname": "template", - "fieldtype": "Dynamic Link", - "in_list_view": 1, - "label": "Template", - "options": "type", - "reqd": 1 - }, - { - "default": "1", - "fieldname": "qty", - "fieldtype": "Int", - "label": "Qty" - }, - { - "fieldname": "instructions", - "fieldtype": "Small Text", - "in_list_view": 1, - "label": "Instructions" - } - ], - "index_web_pages_for_search": 1, - "istable": 1, - "links": [], - "modified": "2021-08-17 11:19:03.515441", - "modified_by": "Administrator", - "module": "Healthcare", - "name": "Treatment Plan Template Item", - "owner": "Administrator", - "permissions": [], - "sort_field": "modified", - "sort_order": "DESC", - "track_changes": 1 -} \ No newline at end of file diff --git a/erpnext/healthcare/doctype/treatment_plan_template_practitioner/__init__.py b/erpnext/healthcare/doctype/treatment_plan_template_practitioner/__init__.py deleted file mode 100644 index e69de29bb2d..00000000000 diff --git a/erpnext/healthcare/doctype/vital_signs/__init__.py b/erpnext/healthcare/doctype/vital_signs/__init__.py deleted file mode 100644 index e69de29bb2d..00000000000 diff --git a/erpnext/healthcare/doctype/vital_signs/test_vital_signs.py b/erpnext/healthcare/doctype/vital_signs/test_vital_signs.py deleted file mode 100644 index 22b52fb4822..00000000000 --- a/erpnext/healthcare/doctype/vital_signs/test_vital_signs.py +++ /dev/null @@ -1,11 +0,0 @@ -# -*- coding: utf-8 -*- -# Copyright (c) 2015, ESS LLP and Contributors -# See license.txt -from __future__ import unicode_literals - -import unittest - -# test_records = frappe.get_test_records('Vital Signs') - -class TestVitalSigns(unittest.TestCase): - pass diff --git a/erpnext/healthcare/doctype/vital_signs/vital_signs.js b/erpnext/healthcare/doctype/vital_signs/vital_signs.js deleted file mode 100644 index 78509e0323c..00000000000 --- a/erpnext/healthcare/doctype/vital_signs/vital_signs.js +++ /dev/null @@ -1,52 +0,0 @@ -// Copyright (c) 2016, ESS LLP and contributors -// For license information, please see license.txt - -frappe.ui.form.on('Vital Signs', { - height: function(frm) { - if (frm.doc.height && frm.doc.weight) { - calculate_bmi(frm); - } - }, - - weight: function(frm) { - if (frm.doc.height && frm.doc.weight) { - calculate_bmi(frm); - } - }, - - bp_systolic: function(frm) { - if (frm.doc.bp_systolic && frm.doc.bp_diastolic) { - set_bp(frm); - } - }, - - bp_diastolic: function(frm) { - if (frm.doc.bp_systolic && frm.doc.bp_diastolic) { - set_bp(frm); - } - } -}); - -let calculate_bmi = function(frm){ - // Reference https://en.wikipedia.org/wiki/Body_mass_index - // bmi = weight (in Kg) / height * height (in Meter) - let bmi = (frm.doc.weight / (frm.doc.height * frm.doc.height)).toFixed(2); - let bmi_note = null; - - if (bmi<18.5) { - bmi_note = 'Underweight'; - } else if (bmi>=18.5 && bmi<25) { - bmi_note = 'Normal'; - } else if (bmi>=25 && bmi<30) { - bmi_note = 'Overweight'; - } else if (bmi>=30) { - bmi_note = 'Obese'; - } - frappe.model.set_value(frm.doctype,frm.docname, 'bmi', bmi); - frappe.model.set_value(frm.doctype,frm.docname, 'nutrition_note', bmi_note); -}; - -let set_bp = function(frm){ - let bp = frm.doc.bp_systolic+ '/' + frm.doc.bp_diastolic + ' mmHg'; - frappe.model.set_value(frm.doctype,frm.docname, 'bp', bp); -}; diff --git a/erpnext/healthcare/doctype/vital_signs/vital_signs.json b/erpnext/healthcare/doctype/vital_signs/vital_signs.json deleted file mode 100644 index 15ab5047bc4..00000000000 --- a/erpnext/healthcare/doctype/vital_signs/vital_signs.json +++ /dev/null @@ -1,305 +0,0 @@ -{ - "actions": [], - "allow_copy": 1, - "allow_import": 1, - "autoname": "naming_series:", - "beta": 1, - "creation": "2017-02-02 11:00:24.853005", - "doctype": "DocType", - "editable_grid": 1, - "engine": "InnoDB", - "field_order": [ - "naming_series", - "title", - "patient", - "patient_name", - "inpatient_record", - "appointment", - "encounter", - "column_break_2", - "company", - "signs_date", - "signs_time", - "sb_vs", - "temperature", - "pulse", - "respiratory_rate", - "tongue", - "abdomen", - "column_break_8", - "reflexes", - "bp_systolic", - "bp_diastolic", - "bp", - "vital_signs_note", - "sb_nutrition_values", - "height", - "weight", - "bmi", - "column_break_14", - "nutrition_note", - "sb_references", - "amended_from" - ], - "fields": [ - { - "fetch_from": "patient.inpatient_record", - "fieldname": "inpatient_record", - "fieldtype": "Link", - "label": "Inpatient Record", - "options": "Inpatient Record", - "read_only": 1 - }, - { - "fetch_from": "inpatient_record.patient", - "fieldname": "patient", - "fieldtype": "Link", - "ignore_user_permissions": 1, - "in_list_view": 1, - "in_standard_filter": 1, - "label": "Patient", - "options": "Patient", - "reqd": 1 - }, - { - "fetch_from": "patient.patient_name", - "fieldname": "patient_name", - "fieldtype": "Data", - "label": "Patient Name", - "read_only": 1 - }, - { - "fieldname": "appointment", - "fieldtype": "Link", - "in_filter": 1, - "label": "Patient Appointment", - "no_copy": 1, - "options": "Patient Appointment", - "print_hide": 1, - "read_only": 1 - }, - { - "fieldname": "encounter", - "fieldtype": "Link", - "in_filter": 1, - "label": "Patient Encounter", - "no_copy": 1, - "options": "Patient Encounter", - "print_hide": 1, - "read_only": 1 - }, - { - "fieldname": "column_break_2", - "fieldtype": "Column Break" - }, - { - "default": "Today", - "fieldname": "signs_date", - "fieldtype": "Date", - "label": "Date", - "reqd": 1 - }, - { - "fieldname": "signs_time", - "fieldtype": "Time", - "label": "Time", - "reqd": 1 - }, - { - "fieldname": "sb_vs", - "fieldtype": "Section Break", - "label": "Vital Signs" - }, - { - "description": "Presence of a fever (temp > 38.5 \u00b0C/101.3 \u00b0F or sustained temp > 38 \u00b0C/100.4 \u00b0F)", - "fieldname": "temperature", - "fieldtype": "Data", - "ignore_xss_filter": 1, - "in_list_view": 1, - "label": "Body Temperature" - }, - { - "description": "Adults' pulse rate is anywhere between 50 and 80 beats per minute.", - "fieldname": "pulse", - "fieldtype": "Data", - "ignore_xss_filter": 1, - "in_list_view": 1, - "label": "Heart Rate / Pulse" - }, - { - "description": "Normal reference range for an adult is 16\u201320 breaths/minute (RCP 2012)", - "fieldname": "respiratory_rate", - "fieldtype": "Data", - "ignore_xss_filter": 1, - "in_list_view": 1, - "label": "Respiratory rate" - }, - { - "fieldname": "tongue", - "fieldtype": "Select", - "label": "Tongue", - "options": "\nCoated\nVery Coated\nNormal\nFurry\nCuts" - }, - { - "fieldname": "abdomen", - "fieldtype": "Select", - "label": "Abdomen", - "options": "\nNormal\nBloated\nFull\nFluid\nConstipated" - }, - { - "fieldname": "column_break_8", - "fieldtype": "Column Break" - }, - { - "fieldname": "reflexes", - "fieldtype": "Select", - "label": "Reflexes", - "options": "\nNormal\nHyper\nVery Hyper\nOne Sided" - }, - { - "fieldname": "bp_systolic", - "fieldtype": "Data", - "ignore_xss_filter": 1, - "in_list_view": 1, - "label": "Blood Pressure (systolic)" - }, - { - "fieldname": "bp_diastolic", - "fieldtype": "Data", - "ignore_xss_filter": 1, - "in_list_view": 1, - "label": "Blood Pressure (diastolic)" - }, - { - "description": "Normal resting blood pressure in an adult is approximately 120 mmHg systolic, and 80 mmHg diastolic, abbreviated \"120/80 mmHg\"", - "fieldname": "bp", - "fieldtype": "Data", - "label": "Blood Pressure", - "read_only": 1 - }, - { - "fieldname": "vital_signs_note", - "fieldtype": "Small Text", - "ignore_xss_filter": 1, - "label": "Notes" - }, - { - "fieldname": "sb_nutrition_values", - "fieldtype": "Section Break", - "label": "Nutrition Values" - }, - { - "fieldname": "height", - "fieldtype": "Float", - "in_list_view": 1, - "label": "Height (In Meter)" - }, - { - "fieldname": "weight", - "fieldtype": "Float", - "in_list_view": 1, - "label": "Weight (In Kilogram)" - }, - { - "default": "0.00", - "fieldname": "bmi", - "fieldtype": "Float", - "in_list_view": 1, - "label": "BMI", - "read_only": 1 - }, - { - "fieldname": "column_break_14", - "fieldtype": "Column Break" - }, - { - "fieldname": "nutrition_note", - "fieldtype": "Small Text", - "ignore_xss_filter": 1, - "label": "Notes" - }, - { - "fieldname": "company", - "fieldtype": "Link", - "label": "Company", - "options": "Company" - }, - { - "fieldname": "amended_from", - "fieldtype": "Link", - "label": "Amended From", - "no_copy": 1, - "options": "Vital Signs", - "print_hide": 1, - "read_only": 1 - }, - { - "collapsible": 1, - "fieldname": "sb_references", - "fieldtype": "Section Break" - }, - { - "fieldname": "naming_series", - "fieldtype": "Select", - "label": "Series", - "options": "HLC-VTS-.YYYY.-", - "reqd": 1 - }, - { - "allow_on_submit": 1, - "columns": 5, - "fieldname": "title", - "fieldtype": "Data", - "hidden": 1, - "label": "Title", - "no_copy": 1, - "print_hide": 1, - "read_only": 1 - } - ], - "is_submittable": 1, - "links": [], - "modified": "2020-05-17 22:23:24.632286", - "modified_by": "Administrator", - "module": "Healthcare", - "name": "Vital Signs", - "owner": "Administrator", - "permissions": [ - { - "cancel": 1, - "create": 1, - "delete": 1, - "email": 1, - "export": 1, - "print": 1, - "read": 1, - "report": 1, - "role": "Physician", - "share": 1, - "submit": 1, - "write": 1 - }, - { - "cancel": 1, - "create": 1, - "delete": 1, - "email": 1, - "export": 1, - "print": 1, - "read": 1, - "report": 1, - "role": "Nursing User", - "share": 1, - "submit": 1, - "write": 1 - } - ], - "restrict_to_domain": "Healthcare", - "search_fields": "patient, signs_date", - "show_name_in_global_search": 1, - "sort_field": "modified", - "sort_order": "DESC", - "title_field": "title", - "track_changes": 1, - "track_seen": 1 -} \ No newline at end of file diff --git a/erpnext/healthcare/doctype/vital_signs/vital_signs.py b/erpnext/healthcare/doctype/vital_signs/vital_signs.py deleted file mode 100644 index 29dbeb470dd..00000000000 --- a/erpnext/healthcare/doctype/vital_signs/vital_signs.py +++ /dev/null @@ -1,18 +0,0 @@ -# -*- coding: utf-8 -*- -# Copyright (c) 2015, ESS LLP and contributors -# For license information, please see license.txt - -from __future__ import unicode_literals - -import frappe -from frappe import _ -from frappe.model.document import Document - - -class VitalSigns(Document): - def validate(self): - self.set_title() - - def set_title(self): - self.title = _('{0} on {1}').format(self.patient_name or self.patient, - frappe.utils.format_date(self.signs_date))[:100] diff --git a/erpnext/healthcare/healthcare_dashboard/healthcare/healthcare.json b/erpnext/healthcare/healthcare_dashboard/healthcare/healthcare.json deleted file mode 100644 index 2fea6682ed2..00000000000 --- a/erpnext/healthcare/healthcare_dashboard/healthcare/healthcare.json +++ /dev/null @@ -1,62 +0,0 @@ -{ - "cards": [ - { - "card": "Total Patients" - }, - { - "card": "Total Patients Admitted" - }, - { - "card": "Open Appointments" - }, - { - "card": "Appointments to Bill" - } - ], - "charts": [ - { - "chart": "Patient Appointments", - "width": "Full" - }, - { - "chart": "In-Patient Status", - "width": "Half" - }, - { - "chart": "Clinical Procedures Status", - "width": "Half" - }, - { - "chart": "Lab Tests", - "width": "Half" - }, - { - "chart": "Clinical Procedures", - "width": "Half" - }, - { - "chart": "Symptoms", - "width": "Half" - }, - { - "chart": "Diagnoses", - "width": "Half" - }, - { - "chart": "Department wise Patient Appointments", - "width": "Full" - } - ], - "creation": "2020-07-14 18:17:54.823311", - "dashboard_name": "Healthcare", - "docstatus": 0, - "doctype": "Dashboard", - "idx": 0, - "is_default": 0, - "is_standard": 1, - "modified": "2020-07-22 15:36:34.220387", - "modified_by": "Administrator", - "module": "Healthcare", - "name": "Healthcare", - "owner": "Administrator" -} \ No newline at end of file diff --git a/erpnext/healthcare/module_onboarding/healthcare/healthcare.json b/erpnext/healthcare/module_onboarding/healthcare/healthcare.json deleted file mode 100644 index 0aa8f9a027e..00000000000 --- a/erpnext/healthcare/module_onboarding/healthcare/healthcare.json +++ /dev/null @@ -1,41 +0,0 @@ -{ - "allow_roles": [ - { - "role": "Healthcare Administrator" - } - ], - "creation": "2020-05-19 10:32:43.025852", - "docstatus": 0, - "doctype": "Module Onboarding", - "documentation_url": "https://docs.erpnext.com/docs/user/manual/en/healthcare", - "idx": 0, - "is_complete": 0, - "modified": "2021-01-30 19:22:20.273766", - "modified_by": "Administrator", - "module": "Healthcare", - "name": "Healthcare", - "owner": "Administrator", - "steps": [ - { - "step": "Create Patient" - }, - { - "step": "Create Practitioner Schedule" - }, - { - "step": "Introduction to Healthcare Practitioner" - }, - { - "step": "Create Healthcare Practitioner" - }, - { - "step": "Explore Healthcare Settings" - }, - { - "step": "Explore Clinical Procedure Templates" - } - ], - "subtitle": "Patients, Practitioner Schedules, Settings, and more.", - "success_message": "The Healthcare Module is all set up!", - "title": "Let's Set Up the Healthcare Module." -} \ No newline at end of file diff --git a/erpnext/healthcare/number_card/appointments_to_bill/appointments_to_bill.json b/erpnext/healthcare/number_card/appointments_to_bill/appointments_to_bill.json deleted file mode 100644 index 3e4d4e27dff..00000000000 --- a/erpnext/healthcare/number_card/appointments_to_bill/appointments_to_bill.json +++ /dev/null @@ -1,21 +0,0 @@ -{ - "creation": "2020-07-14 18:17:54.792773", - "docstatus": 0, - "doctype": "Number Card", - "document_type": "Patient Appointment", - "dynamic_filters_json": "[[\"Patient Appointment\",\"company\",\"=\",\"frappe.defaults.get_user_default(\\\"Company\\\")\"]]", - "filters_json": "[[\"Patient Appointment\",\"invoiced\",\"=\",0,false]]", - "function": "Count", - "idx": 0, - "is_public": 1, - "is_standard": 1, - "label": "Appointments To Bill", - "modified": "2020-07-22 13:27:58.038577", - "modified_by": "Administrator", - "module": "Healthcare", - "name": "Appointments to Bill", - "owner": "Administrator", - "show_percentage_stats": 1, - "stats_time_interval": "Daily", - "type": "Document Type" -} \ No newline at end of file diff --git a/erpnext/healthcare/number_card/open_appointments/open_appointments.json b/erpnext/healthcare/number_card/open_appointments/open_appointments.json deleted file mode 100644 index 8d121cc58a6..00000000000 --- a/erpnext/healthcare/number_card/open_appointments/open_appointments.json +++ /dev/null @@ -1,21 +0,0 @@ -{ - "creation": "2020-07-14 18:17:54.771092", - "docstatus": 0, - "doctype": "Number Card", - "document_type": "Patient Appointment", - "dynamic_filters_json": "[[\"Patient Appointment\",\"company\",\"=\",\"frappe.defaults.get_user_default(\\\"Company\\\")\"]]", - "filters_json": "[[\"Patient Appointment\",\"status\",\"=\",\"Open\",false]]", - "function": "Count", - "idx": 0, - "is_public": 1, - "is_standard": 1, - "label": "Open Appointments", - "modified": "2020-07-22 13:27:09.542122", - "modified_by": "Administrator", - "module": "Healthcare", - "name": "Open Appointments", - "owner": "Administrator", - "show_percentage_stats": 1, - "stats_time_interval": "Daily", - "type": "Document Type" -} \ No newline at end of file diff --git a/erpnext/healthcare/number_card/total_patients/total_patients.json b/erpnext/healthcare/number_card/total_patients/total_patients.json deleted file mode 100644 index 75441a6842d..00000000000 --- a/erpnext/healthcare/number_card/total_patients/total_patients.json +++ /dev/null @@ -1,20 +0,0 @@ -{ - "creation": "2020-07-14 18:17:54.727946", - "docstatus": 0, - "doctype": "Number Card", - "document_type": "Patient", - "filters_json": "[[\"Patient\",\"status\",\"=\",\"Active\",false]]", - "function": "Count", - "idx": 0, - "is_public": 1, - "is_standard": 1, - "label": "Total Patients", - "modified": "2020-07-22 13:26:02.643534", - "modified_by": "Administrator", - "module": "Healthcare", - "name": "Total Patients", - "owner": "Administrator", - "show_percentage_stats": 1, - "stats_time_interval": "Daily", - "type": "Document Type" -} \ No newline at end of file diff --git a/erpnext/healthcare/number_card/total_patients_admitted/total_patients_admitted.json b/erpnext/healthcare/number_card/total_patients_admitted/total_patients_admitted.json deleted file mode 100644 index 69a967df938..00000000000 --- a/erpnext/healthcare/number_card/total_patients_admitted/total_patients_admitted.json +++ /dev/null @@ -1,20 +0,0 @@ -{ - "creation": "2020-07-14 18:17:54.749754", - "docstatus": 0, - "doctype": "Number Card", - "document_type": "Patient", - "filters_json": "[[\"Patient\",\"inpatient_status\",\"=\",\"Admitted\",false]]", - "function": "Count", - "idx": 0, - "is_public": 1, - "is_standard": 1, - "label": "Total Patients Admitted", - "modified": "2020-07-22 13:26:20.027788", - "modified_by": "Administrator", - "module": "Healthcare", - "name": "Total Patients Admitted", - "owner": "Administrator", - "show_percentage_stats": 1, - "stats_time_interval": "Daily", - "type": "Document Type" -} \ No newline at end of file diff --git a/erpnext/healthcare/onboarding_step/create_healthcare_practitioner/create_healthcare_practitioner.json b/erpnext/healthcare/onboarding_step/create_healthcare_practitioner/create_healthcare_practitioner.json deleted file mode 100644 index 3f25a9d6760..00000000000 --- a/erpnext/healthcare/onboarding_step/create_healthcare_practitioner/create_healthcare_practitioner.json +++ /dev/null @@ -1,19 +0,0 @@ -{ - "action": "Create Entry", - "creation": "2020-05-19 10:39:55.728058", - "docstatus": 0, - "doctype": "Onboarding Step", - "idx": 0, - "is_complete": 0, - "is_single": 0, - "is_skipped": 0, - "modified": "2021-01-30 12:02:22.849260", - "modified_by": "Administrator", - "name": "Create Healthcare Practitioner", - "owner": "Administrator", - "reference_document": "Healthcare Practitioner", - "show_form_tour": 0, - "show_full_form": 1, - "title": "Create Healthcare Practitioner", - "validate_action": 1 -} \ No newline at end of file diff --git a/erpnext/healthcare/onboarding_step/create_patient/create_patient.json b/erpnext/healthcare/onboarding_step/create_patient/create_patient.json deleted file mode 100644 index b46bb15b48a..00000000000 --- a/erpnext/healthcare/onboarding_step/create_patient/create_patient.json +++ /dev/null @@ -1,19 +0,0 @@ -{ - "action": "Create Entry", - "creation": "2020-05-19 10:32:27.648902", - "docstatus": 0, - "doctype": "Onboarding Step", - "idx": 0, - "is_complete": 0, - "is_single": 0, - "is_skipped": 0, - "modified": "2021-01-30 00:09:28.786428", - "modified_by": "ruchamahabal2@gmail.com", - "name": "Create Patient", - "owner": "Administrator", - "reference_document": "Patient", - "show_form_tour": 0, - "show_full_form": 1, - "title": "Create Patient", - "validate_action": 1 -} \ No newline at end of file diff --git a/erpnext/healthcare/onboarding_step/create_practitioner_schedule/create_practitioner_schedule.json b/erpnext/healthcare/onboarding_step/create_practitioner_schedule/create_practitioner_schedule.json deleted file mode 100644 index 7ce122d5c0b..00000000000 --- a/erpnext/healthcare/onboarding_step/create_practitioner_schedule/create_practitioner_schedule.json +++ /dev/null @@ -1,19 +0,0 @@ -{ - "action": "Create Entry", - "creation": "2020-05-19 10:41:19.065753", - "docstatus": 0, - "doctype": "Onboarding Step", - "idx": 0, - "is_complete": 0, - "is_single": 0, - "is_skipped": 0, - "modified": "2021-01-30 00:09:28.794602", - "modified_by": "ruchamahabal2@gmail.com", - "name": "Create Practitioner Schedule", - "owner": "Administrator", - "reference_document": "Practitioner Schedule", - "show_form_tour": 0, - "show_full_form": 1, - "title": "Create Practitioner Schedule", - "validate_action": 1 -} \ No newline at end of file diff --git a/erpnext/healthcare/onboarding_step/explore_clinical_procedure_templates/explore_clinical_procedure_templates.json b/erpnext/healthcare/onboarding_step/explore_clinical_procedure_templates/explore_clinical_procedure_templates.json deleted file mode 100644 index dfe9f71a76f..00000000000 --- a/erpnext/healthcare/onboarding_step/explore_clinical_procedure_templates/explore_clinical_procedure_templates.json +++ /dev/null @@ -1,19 +0,0 @@ -{ - "action": "Show Form Tour", - "creation": "2020-05-19 11:40:51.963741", - "docstatus": 0, - "doctype": "Onboarding Step", - "idx": 0, - "is_complete": 0, - "is_single": 0, - "is_skipped": 0, - "modified": "2021-01-30 19:22:08.257160", - "modified_by": "Administrator", - "name": "Explore Clinical Procedure Templates", - "owner": "Administrator", - "reference_document": "Clinical Procedure Template", - "show_form_tour": 0, - "show_full_form": 0, - "title": "Explore Clinical Procedure Templates", - "validate_action": 1 -} \ No newline at end of file diff --git a/erpnext/healthcare/onboarding_step/explore_healthcare_settings/explore_healthcare_settings.json b/erpnext/healthcare/onboarding_step/explore_healthcare_settings/explore_healthcare_settings.json deleted file mode 100644 index 2d952f30938..00000000000 --- a/erpnext/healthcare/onboarding_step/explore_healthcare_settings/explore_healthcare_settings.json +++ /dev/null @@ -1,19 +0,0 @@ -{ - "action": "Show Form Tour", - "creation": "2020-05-19 11:14:33.044989", - "docstatus": 0, - "doctype": "Onboarding Step", - "idx": 0, - "is_complete": 0, - "is_single": 1, - "is_skipped": 0, - "modified": "2021-01-30 19:22:07.275735", - "modified_by": "Administrator", - "name": "Explore Healthcare Settings", - "owner": "Administrator", - "reference_document": "Healthcare Settings", - "show_form_tour": 0, - "show_full_form": 0, - "title": "Explore Healthcare Settings", - "validate_action": 1 -} \ No newline at end of file diff --git a/erpnext/healthcare/onboarding_step/introduction_to_healthcare_practitioner/introduction_to_healthcare_practitioner.json b/erpnext/healthcare/onboarding_step/introduction_to_healthcare_practitioner/introduction_to_healthcare_practitioner.json deleted file mode 100644 index baa8358c060..00000000000 --- a/erpnext/healthcare/onboarding_step/introduction_to_healthcare_practitioner/introduction_to_healthcare_practitioner.json +++ /dev/null @@ -1,20 +0,0 @@ -{ - "action": "Show Form Tour", - "creation": "2020-05-19 10:43:56.231679", - "docstatus": 0, - "doctype": "Onboarding Step", - "field": "schedule", - "idx": 0, - "is_complete": 0, - "is_single": 0, - "is_skipped": 0, - "modified": "2021-01-30 00:09:28.807129", - "modified_by": "ruchamahabal2@gmail.com", - "name": "Introduction to Healthcare Practitioner", - "owner": "Administrator", - "reference_document": "Healthcare Practitioner", - "show_form_tour": 0, - "show_full_form": 0, - "title": "Introduction to Healthcare Practitioner", - "validate_action": 0 -} \ No newline at end of file diff --git a/erpnext/healthcare/page/__init__.py b/erpnext/healthcare/page/__init__.py deleted file mode 100644 index baffc488252..00000000000 --- a/erpnext/healthcare/page/__init__.py +++ /dev/null @@ -1 +0,0 @@ -from __future__ import unicode_literals diff --git a/erpnext/healthcare/page/patient_history/__init__.py b/erpnext/healthcare/page/patient_history/__init__.py deleted file mode 100644 index e69de29bb2d..00000000000 diff --git a/erpnext/healthcare/page/patient_history/patient_history.css b/erpnext/healthcare/page/patient_history/patient_history.css deleted file mode 100644 index 74b5e7eb918..00000000000 --- a/erpnext/healthcare/page/patient_history/patient_history.css +++ /dev/null @@ -1,151 +0,0 @@ -#page-medical_record .label { - display: inline-block; - margin-right: 7px; -} - -#page-medical_record .list-row { - border: none; - padding: 0px; - cursor: pointer; -} - -.patient-image-container { - margin-top: 17px; - } - -.patient-image { - display: inline-block; - width: 100%; - height: 0; - padding: 50% 0px; - background-size: cover; - background-repeat: no-repeat; - background-position: center center; - border-radius: 4px; -} - -.patient-name { - font-size: 20px; - margin-top: 25px; -} - -.medical_record-label { - max-width: 100px; - margin-bottom: -4px; -} - -.medical_record-row > * { - z-index: -999; -} - -.date-indicator { - background:none; - font-size:12px; - vertical-align:middle; - font-weight:bold; - color:#6c7680; -} -.date-indicator::after { - margin:0 -4px 0 12px; - content:''; - display:inline-block; - height:8px; - width:8px; - border-radius:8px; - background: #d1d8dd; -} - -.date-indicator.blue { - color: #5e64ff; -} - -.div-bg-color { - background: #fafbfc; -} - -.bg-color-white { - background: #FFFFFF; -} - -.d-flex { - display: flex; -} - -.width-full { - width: 100%; -} - -.p-3 { - padding: 16px; -} - -.mt-2 { - margin-top: 8px; -} - -.mr-3 { - margin-right: 16px; -} - -.Box { - background-color: #fff; - border: 1px solid #d1d5da; - border-radius: 3px; -} - -.flex-column { - flex-direction: column; -} - -.avatar { - display: inline-block; - overflow: hidden; - line-height: 1; - vertical-align: middle; - border-radius: 3px; -} - -.py-3 { - padding-top: 16px; - padding-bottom: 16px; -} - -.border-bottom { - border-bottom: 1px #e1e4e8 solid; -} - -.date-indicator.blue::after { - background: #5e64ff; -} - -.medical_record-message { - border-left: 1px solid #d1d8dd; - padding: 15px; - padding-right: 30px; -} - -.medical_record-date { - padding: 15px; - padding-right: 0px; -} - -.patient-history-filter { - margin-left: 35px; - width: 25%; -} - -#page-medical_record .plot-wrapper { - padding: 20px 15px; - border-bottom: 1px solid #d1d8dd; - text-align: center; -} - -#page-medical_record .plot { - height: 140px ; - width: 97% ; - margin: auto; -} - -#page-medical_record .list-filters { - display: none ; -} diff --git a/erpnext/healthcare/page/patient_history/patient_history.html b/erpnext/healthcare/page/patient_history/patient_history.html deleted file mode 100644 index d16b38637cd..00000000000 --- a/erpnext/healthcare/page/patient_history/patient_history.html +++ /dev/null @@ -1,18 +0,0 @@ -
-
-
-
-
-
-
- -
-
-
-
-
-
-
- -
-
diff --git a/erpnext/healthcare/page/patient_history/patient_history.js b/erpnext/healthcare/page/patient_history/patient_history.js deleted file mode 100644 index ed2dc52cb11..00000000000 --- a/erpnext/healthcare/page/patient_history/patient_history.js +++ /dev/null @@ -1,455 +0,0 @@ -frappe.provide('frappe.patient_history'); -frappe.pages['patient_history'].on_page_load = function(wrapper) { - frappe.ui.make_app_page({ - parent: wrapper, - title: __('Patient History') - }); - - let patient_history = new PatientHistory(wrapper); - $(wrapper).bind('show', ()=> { - patient_history.show(); - }); -}; - -class PatientHistory { - constructor(wrapper) { - this.wrapper = $(wrapper); - this.page = wrapper.page; - this.sidebar = this.wrapper.find('.layout-side-section'); - this.main_section = this.wrapper.find('.layout-main-section'); - this.start = 0; - } - - show() { - frappe.breadcrumbs.add('Healthcare'); - this.sidebar.empty(); - - let me = this; - let patient = frappe.ui.form.make_control({ - parent: me.sidebar, - df: { - fieldtype: 'Link', - options: 'Patient', - fieldname: 'patient', - placeholder: __('Select Patient'), - only_select: true, - change: () => { - me.patient_id = ''; - if (me.patient_id != patient.get_value() && patient.get_value()) { - me.start = 0; - me.patient_id = patient.get_value(); - me.make_patient_profile(); - } - } - } - }); - patient.refresh(); - - if (frappe.route_options && !this.patient_id) { - patient.set_value(frappe.route_options.patient); - this.patient_id = frappe.route_options.patient; - } - - this.sidebar.find('[data-fieldname="patient"]').append('
'); - } - - make_patient_profile() { - this.page.set_title(__('Patient History')); - this.main_section.empty().append(frappe.render_template('patient_history')); - this.setup_filters(); - this.setup_documents(); - this.show_patient_info(); - this.setup_buttons(); - this.show_patient_vital_charts('bp', 'mmHg', 'Blood Pressure'); - } - - setup_filters() { - $('.doctype-filter').empty(); - let me = this; - - frappe.xcall( - 'erpnext.healthcare.page.patient_history.patient_history.get_patient_history_doctypes' - ).then(document_types => { - let doctype_filter = frappe.ui.form.make_control({ - parent: $('.doctype-filter'), - df: { - fieldtype: 'MultiSelectList', - fieldname: 'document_type', - placeholder: __('Select Document Type'), - change: () => { - me.start = 0; - me.page.main.find('.patient_documents_list').html(''); - this.setup_documents(doctype_filter.get_value(), date_range_field.get_value()); - }, - get_data: () => { - return document_types.map(document_type => { - return { - description: document_type, - value: document_type - }; - }); - }, - } - }); - doctype_filter.refresh(); - - $('.date-filter').empty(); - let date_range_field = frappe.ui.form.make_control({ - df: { - fieldtype: 'DateRange', - fieldname: 'date_range', - placeholder: __('Date Range'), - input_class: 'input-xs', - change: () => { - let selected_date_range = date_range_field.get_value(); - if (selected_date_range && selected_date_range.length === 2) { - me.start = 0; - me.page.main.find('.patient_documents_list').html(''); - this.setup_documents(doctype_filter.get_value(), date_range_field.get_value()); - } - } - }, - parent: $('.date-filter') - }); - date_range_field.refresh(); - }); - } - - setup_documents(document_types="", selected_date_range="") { - let filters = { - name: this.patient_id, - start: this.start, - page_length: 20 - }; - if (document_types) - filters['document_types'] = document_types; - if (selected_date_range) - filters['date_range'] = selected_date_range; - - let me = this; - frappe.call({ - 'method': 'erpnext.healthcare.page.patient_history.patient_history.get_feed', - args: filters, - callback: function(r) { - let data = r.message; - if (data.length) { - me.add_to_records(data); - } else { - me.page.main.find('.patient_documents_list').append(` -
-

${__('No more records..')}

-
`); - me.page.main.find('.btn-get-records').hide(); - } - } - }); - } - - add_to_records(data) { - let details = ""; - let i; - for (i=0; i - ${data[i].reference_name} - `; - - details += ` -
-
`; - - if (data[i].imgsrc) { - details += ` - - `; - } else { - details += ` -
- ${data[i].practitioner ? data[i].practitioner.charAt(0) : 'U'} -
-
`; - } - - details += `
-
- `+time_line_heading+` - - ${data[i].date_sep} - -
-
- ${label} -
-
- - -
-
- - -
-
-
-
`; - } - } - - this.page.main.find('.patient_documents_list').append(details); - this.start += data.length; - - if (data.length === 20) { - this.page.main.find(".btn-get-records").show(); - } else { - this.page.main.find(".btn-get-records").hide(); - this.page.main.find(".patient_documents_list").append(` -
-

${__('No more records..')}

-
`); - } - } - - add_date_separator(data) { - let date = frappe.datetime.str_to_obj(data.communication_date); - let pdate = ''; - let diff = frappe.datetime.get_day_diff(frappe.datetime.get_today(), - frappe.datetime.obj_to_str(date)); - - if (diff < 1) { - pdate = __('Today'); - } else if (diff < 2) { - pdate = __('Yesterday'); - } else { - pdate = __('on {0}', [frappe.datetime.global_date_format(date)]); - } - data.date_sep = pdate; - return data; - } - - show_patient_info() { - this.get_patient_info().then(() => { - $('.patient-info').empty().append(frappe.render_template('patient_history_sidebar', { - patient_image: this.patient.image, - patient_name: this.patient.patient_name, - patient_gender: this.patient.sex, - patient_mobile: this.patient.mobile - })); - this.show_patient_details(); - }); - } - - show_patient_details() { - let me = this; - frappe.call({ - 'method': 'erpnext.healthcare.doctype.patient.patient.get_patient_detail', - args: { - patient: me.patient_id - }, - callback: function(r) { - let data = r.message; - let details = ``; - - if (data.occupation) details += `

${__('Occupation')} : ${data.occupation}`; - if (data.blood_group) details += `
${__('Blood Group')} : ${data.blood_group}`; - if (data.allergies) details += `

${__('Allerigies')} : ${data.allergies.replace("\n", ", ")}`; - if (data.medication) details += `
${__('Medication')} : ${data.medication.replace("\n", ", ")}`; - if (data.alcohol_current_use) details += `

${__('Alcohol use')} : ${data.alcohol_current_use}`; - if (data.alcohol_past_use) details += `
${__('Alcohol past use')} : ${data.alcohol_past_use}`; - if (data.tobacco_current_use) details += `
${__('Tobacco use')} : ${data.tobacco_current_use}`; - if (data.tobacco_past_use) details += `
${__('Tobacco past use')} : ${data.tobacco_past_use}`; - if (data.medical_history) details += `

${__('Medical history')} : ${data.medical_history.replace("\n", ", ")}`; - if (data.surgical_history) details += `
${__('Surgical history')} : ${data.surgical_history.replace("\n", ", ")}`; - if (data.surrounding_factors) details += `

${__('Occupational hazards')} : ${data.surrounding_factors.replace("\n", ", ")}`; - if (data.other_risk_factors) details += `
${__('Other risk factors')} : ${data.other_risk_factors.replace("\n", ", ")}`; - if (data.patient_details) details += `

${__('More info')} : ${data.patient_details.replace("\n", ", ")}`; - - if (details) { - details = `
` + details + `
`; - } - - me.sidebar.find('.patient-details').html(details); - } - }); - } - - get_patient_info() { - return frappe.xcall('frappe.client.get', { - doctype: 'Patient', - name: this.patient_id, - }).then((patient) => { - if (patient) { - this.patient = patient; - } - }); - } - - setup_buttons() { - let me = this; - this.page.main.on("click", ".btn-show-chart", function() { - let btn_id = $(this).attr("data-show-chart-id"), scale_unit = $(this).attr("data-pts"); - let title = $(this).attr("data-title"); - me.show_patient_vital_charts(btn_id, scale_unit, title); - }); - - this.page.main.on('click', '.btn-more', function() { - let doctype = $(this).attr('data-doctype'), docname = $(this).attr('data-docname'); - if (me.page.main.find('.'+docname).parent().find('.document-html').attr('data-fetched') == '1') { - me.page.main.find('.'+docname).hide(); - me.page.main.find('.'+docname).parent().find('.document-html').show(); - } else { - if (doctype && docname) { - let exclude = ['patient', 'patient_name', 'patient_sex', 'encounter_date', 'naming_series']; - frappe.call({ - method: 'erpnext.healthcare.utils.render_doc_as_html', - args: { - doctype: doctype, - docname: docname, - exclude_fields: exclude - }, - freeze: true, - callback: function(r) { - if (r.message) { - me.page.main.find('.' + docname).hide(); - - me.page.main.find('.' + docname).parent().find('.document-html').html( - `${r.message.html} -
-
- - -
- `); - - me.page.main.find('.' + docname).parent().find('.document-html').attr('hidden', false); - me.page.main.find('.' + docname).parent().find('.document-html').attr('data-fetched', '1'); - } - } - }); - } - } - }); - - this.page.main.on('click', '.btn-less', function() { - let docname = $(this).attr('data-docname'); - me.page.main.find('.' + docname).parent().find('.document-id').show(); - me.page.main.find('.' + docname).parent().find('.document-html').hide(); - }); - - me.page.main.on('click', '.btn-get-records', function() { - this.setup_documents(); - }); - } - - show_patient_vital_charts(btn_id, scale_unit, title) { - let me = this; - - frappe.call({ - method: 'erpnext.healthcare.utils.get_patient_vitals', - args: { - patient: me.patient_id - }, - callback: function(r) { - if (r.message) { - let show_chart_btns_html = ` -
- - ${__('Blood Pressure')} - - - ${__('Respiratory/Pulse Rate')} - - - ${__('Temperature')} - - - ${__('BMI')} - -
`; - - me.page.main.find('.show_chart_btns').html(show_chart_btns_html); - let data = r.message; - let labels = [], datasets = []; - let bp_systolic = [], bp_diastolic = [], temperature = []; - let pulse = [], respiratory_rate = [], bmi = [], height = [], weight = []; - - for (let i=0; i (d + '').toUpperCase(), - formatTooltipY: d => d + ' ' + scale_unit, - } - }); - me.page.main.find('.header-separator').show(); - } else { - me.page.main.find('.patient_vital_charts').html(''); - me.page.main.find('.show_chart_btns').html(''); - me.page.main.find('.header-separator').hide(); - } - } - }); - } -} diff --git a/erpnext/healthcare/page/patient_history/patient_history.json b/erpnext/healthcare/page/patient_history/patient_history.json deleted file mode 100644 index b3892a41c60..00000000000 --- a/erpnext/healthcare/page/patient_history/patient_history.json +++ /dev/null @@ -1,28 +0,0 @@ -{ - "content": null, - "creation": "2018-08-08 17:09:13.816199", - "docstatus": 0, - "doctype": "Page", - "icon": "", - "idx": 0, - "modified": "2018-08-08 17:09:55.969424", - "modified_by": "Administrator", - "module": "Healthcare", - "name": "patient_history", - "owner": "Administrator", - "page_name": "patient_history", - "restrict_to_domain": "Healthcare", - "roles": [ - { - "role": "Healthcare Administrator" - }, - { - "role": "Physician" - } - ], - "script": null, - "standard": "Yes", - "style": null, - "system_page": 0, - "title": "Patient History" -} \ No newline at end of file diff --git a/erpnext/healthcare/page/patient_history/patient_history.py b/erpnext/healthcare/page/patient_history/patient_history.py deleted file mode 100644 index 77d8846f373..00000000000 --- a/erpnext/healthcare/page/patient_history/patient_history.py +++ /dev/null @@ -1,75 +0,0 @@ -# -*- coding: utf-8 -*- -# Copyright (c) 2018, ESS LLP and contributors -# For license information, please see license.txt - -from __future__ import unicode_literals - -import json - -import frappe -from frappe.utils import cint - - -@frappe.whitelist() -def get_feed(name, document_types=None, date_range=None, start=0, page_length=20): - """get feed""" - filters = get_filters(name, document_types, date_range) - - result = frappe.db.get_all('Patient Medical Record', - fields=['name', 'owner', 'communication_date', - 'reference_doctype', 'reference_name', 'subject'], - filters=filters, - order_by='communication_date DESC', - limit=cint(page_length), - start=cint(start) - ) - - return result - - -def get_filters(name, document_types=None, date_range=None): - filters = {'patient': name} - if document_types: - document_types = json.loads(document_types) - if len(document_types): - filters['reference_doctype'] = ['IN', document_types] - - if date_range: - try: - date_range = json.loads(date_range) - if date_range: - filters['communication_date'] = ['between', [date_range[0], date_range[1]]] - except json.decoder.JSONDecodeError: - pass - - return filters - - -@frappe.whitelist() -def get_feed_for_dt(doctype, docname): - """get feed""" - result = frappe.db.get_all('Patient Medical Record', - fields=['name', 'owner', 'communication_date', - 'reference_doctype', 'reference_name', 'subject'], - filters={ - 'reference_doctype': doctype, - 'reference_name': docname - }, - order_by='communication_date DESC' - ) - - return result - - -@frappe.whitelist() -def get_patient_history_doctypes(): - document_types = [] - settings = frappe.get_single("Patient History Settings") - - for entry in settings.standard_doctypes: - document_types.append(entry.document_type) - - for entry in settings.custom_doctypes: - document_types.append(entry.document_type) - - return document_types diff --git a/erpnext/healthcare/page/patient_history/patient_history_sidebar.html b/erpnext/healthcare/page/patient_history/patient_history_sidebar.html deleted file mode 100644 index fc7eab05401..00000000000 --- a/erpnext/healthcare/page/patient_history/patient_history_sidebar.html +++ /dev/null @@ -1,20 +0,0 @@ -
-
- {% if patient_image %} -
- {% endif %} -
-
- {% if patient_name %} -

{{patient_name}}

- {% endif %} - {% if patient_gender %} -

{%=__("Gender: ") %} {{patient_gender}}

- {% endif %} - {% if patient_mobile %} -

{%=__("Contact: ") %} {{patient_mobile}}

- {% endif %} -
-
-
-
diff --git a/erpnext/healthcare/page/patient_progress/__init__.py b/erpnext/healthcare/page/patient_progress/__init__.py deleted file mode 100644 index e69de29bb2d..00000000000 diff --git a/erpnext/healthcare/page/patient_progress/patient_progress.css b/erpnext/healthcare/page/patient_progress/patient_progress.css deleted file mode 100644 index 737b2e0ea28..00000000000 --- a/erpnext/healthcare/page/patient_progress/patient_progress.css +++ /dev/null @@ -1,171 +0,0 @@ -/* sidebar */ - -.layout-side-section .frappe-control[data-fieldname='patient'] { - max-width: 300px; -} - -.patient-image-container { - margin-top: 17px; -} - -.patient-image { - display: inline-block; - width: 100%; - height: 0; - padding: 50% 0px; - background-size: cover; - background-repeat: no-repeat; - background-position: center center; - border-radius: 4px; -} - -.patient-details { - margin: -5px 5px; -} - -.important-links { - margin: 30px 5px; -} - -.patient-name { - font-size: 20px; - margin-top: 25px; -} - -/* heatmap */ - -.heatmap-container { - height: 170px; -} - -.patient-heatmap { - width: 80%; - display: inline-block; -} - -.patient-heatmap .chart-container { - margin-left: 30px; -} - -.patient-heatmap .frappe-chart { - margin-top: 5px; -} - -.patient-heatmap .frappe-chart .chart-legend { - display: none; -} - -.heatmap-container .chart-filter { - z-index: 1; - position: relative; - top: 5px; - margin-right: 10px; -} - -/* percentage chart */ - -.percentage-chart-container { - height: 130px; -} - -.percentage-chart-container .chart-filter { - position: relative; - top: 5px; - margin-right: 10px; -} - -.therapy-session-percentage-chart .frappe-chart { - position: absolute; - top: 5px; -} - -/* line charts */ - -.date-field .clearfix { - display: none; -} - -.date-field .help-box { - display: none; -} - -.date-field .frappe-control { - margin-bottom: 0px !important; -} - -.date-field .form-group { - margin-bottom: 0px !important; -} - -/* common */ - -text.title { - text-transform: uppercase; - font-size: 11px; - margin-left: 20px; - margin-top: 20px; - display: block; -} - -.chart-filter-search { - margin-left: 35px; - width: 25%; -} - -.chart-column-container { - margin: 5px 0; -} - -.progress-graphs .progress-container { - margin-bottom: var(--margin-xl); -} - -.line-chart-container .frappe-chart { - margin-top: -20px; -} - -.line-chart-container { - margin-bottom: 20px; -} - -.chart-control { - align-self: center; - display: flex; - flex-direction: row-reverse; - margin-top: -25px; -} - -.chart-control > * { - margin-right: 10px; -} - -/* mobile */ - -@media (max-width: 991px) { - .patient-progress-sidebar { - display: flex; - } - - .percentage-chart-container { - border-top: 1px solid #d1d8dd; - } - - .percentage-chart-container .chart-filter { - z-index: 1; - position: relative; - top: 12px; - margin-right: 10px; - } - - .patient-progress-sidebar .important-links { - margin: 0; - } - - .patient-progress-sidebar .patient-details { - width: 50%; - } - - .chart-filter-search { - width: 40%; - } -} diff --git a/erpnext/healthcare/page/patient_progress/patient_progress.html b/erpnext/healthcare/page/patient_progress/patient_progress.html deleted file mode 100644 index ee60065618f..00000000000 --- a/erpnext/healthcare/page/patient_progress/patient_progress.html +++ /dev/null @@ -1,69 +0,0 @@ -
-
-
- - -
-
-
- -
-
- Therapy Progress -
-
-
- -
-
-
-
-
-
- -
-
- Assessment Results -
-
-
- -
-
-
-
-
-
- -
-
- Therapy Type and Assessment Correlation -
-
-
- -
-
-
-
-
-
- -
-
- Assessment Parameter Wise Progress -
-
-
- -
-
-
-
-
-
-
-
-
diff --git a/erpnext/healthcare/page/patient_progress/patient_progress.js b/erpnext/healthcare/page/patient_progress/patient_progress.js deleted file mode 100644 index 3f06f1feba6..00000000000 --- a/erpnext/healthcare/page/patient_progress/patient_progress.js +++ /dev/null @@ -1,536 +0,0 @@ -frappe.pages['patient-progress'].on_page_load = function(wrapper) { - - frappe.ui.make_app_page({ - parent: wrapper, - title: __('Patient Progress') - }); - - let patient_progress = new PatientProgress(wrapper); - $(wrapper).bind('show', ()=> { - patient_progress.show(); - }); -}; - -class PatientProgress { - - constructor(wrapper) { - this.wrapper = $(wrapper); - this.page = wrapper.page; - this.sidebar = this.wrapper.find('.layout-side-section'); - this.main_section = this.wrapper.find('.layout-main-section'); - } - - show() { - frappe.breadcrumbs.add('Healthcare'); - this.sidebar.empty(); - - let me = this; - let patient = frappe.ui.form.make_control({ - parent: me.sidebar, - df: { - fieldtype: 'Link', - options: 'Patient', - fieldname: 'patient', - placeholder: __('Select Patient'), - only_select: true, - change: () => { - me.patient_id = ''; - if (me.patient_id != patient.get_value() && patient.get_value()) { - me.start = 0; - me.patient_id = patient.get_value(); - me.make_patient_profile(); - } - } - } - }); - patient.refresh(); - - if (frappe.route_options && !this.patient) { - patient.set_value(frappe.route_options.patient); - this.patient_id = frappe.route_options.patient; - } - - this.sidebar.find('[data-fieldname="patient"]').append('
'); - } - - make_patient_profile() { - this.page.set_title(__('Patient Progress')); - this.main_section.empty().append(frappe.render_template('patient_progress')); - this.render_patient_details(); - this.render_heatmap(); - this.render_percentage_chart('therapy_type', 'Therapy Type Distribution'); - this.create_percentage_chart_filters(); - this.show_therapy_progress(); - this.show_assessment_results(); - this.show_therapy_assessment_correlation(); - this.show_assessment_parameter_progress(); - } - - get_patient_info() { - return frappe.xcall('frappe.client.get', { - doctype: 'Patient', - name: this.patient_id - }).then((patient) => { - if (patient) { - this.patient = patient; - } - }); - } - - get_therapy_sessions_count() { - return frappe.xcall( - 'erpnext.healthcare.page.patient_progress.patient_progress.get_therapy_sessions_count', { - patient: this.patient_id, - } - ).then(data => { - if (data) { - this.total_therapy_sessions = data.total_therapy_sessions; - this.therapy_sessions_this_month = data.therapy_sessions_this_month; - } - }); - } - - render_patient_details() { - this.get_patient_info().then(() => { - this.get_therapy_sessions_count().then(() => { - $('.patient-info').empty().append(frappe.render_template('patient_progress_sidebar', { - patient_image: this.patient.image, - patient_name: this.patient.patient_name, - patient_gender: this.patient.sex, - patient_mobile: this.patient.mobile, - total_therapy_sessions: this.total_therapy_sessions, - therapy_sessions_this_month: this.therapy_sessions_this_month - })); - - this.setup_patient_profile_links(); - }); - }); - } - - setup_patient_profile_links() { - this.wrapper.find('.patient-profile-link').on('click', () => { - frappe.set_route('Form', 'Patient', this.patient_id); - }); - - this.wrapper.find('.therapy-plan-link').on('click', () => { - frappe.route_options = { - 'patient': this.patient_id, - 'docstatus': 1 - }; - frappe.set_route('List', 'Therapy Plan'); - }); - - this.wrapper.find('.patient-history').on('click', () => { - frappe.route_options = { - 'patient': this.patient_id - }; - frappe.set_route('patient_history'); - }); - } - - render_heatmap() { - this.heatmap = new frappe.Chart('.patient-heatmap', { - type: 'heatmap', - countLabel: 'Interactions', - data: {}, - discreteDomains: 1, - radius: 3, - height: 150 - }); - - this.update_heatmap_data(); - this.create_heatmap_chart_filters(); - } - - update_heatmap_data(date_from) { - frappe.xcall('erpnext.healthcare.page.patient_progress.patient_progress.get_patient_heatmap_data', { - patient: this.patient_id, - date: date_from || frappe.datetime.year_start(), - }).then((data) => { - this.heatmap.update( {dataPoints: data} ); - }); - } - - create_heatmap_chart_filters() { - this.get_patient_info().then(() => { - let filters = [ - { - label: frappe.dashboard_utils.get_year(frappe.datetime.now_date()), - options: frappe.dashboard_utils.get_years_since_creation(this.patient.creation), - action: (selected_item) => { - this.update_heatmap_data(frappe.datetime.obj_to_str(selected_item)); - } - }, - ]; - frappe.dashboard_utils.render_chart_filters(filters, 'chart-filter', '.heatmap-container'); - }); - } - - render_percentage_chart(field, title) { - // REDESIGN-TODO: chart seems to be broken. Enable this once fixed. - this.wrapper.find('.percentage-chart-container').hide(); - // frappe.xcall( - // 'erpnext.healthcare.page.patient_progress.patient_progress.get_therapy_sessions_distribution_data', { - // patient: this.patient_id, - // field: field - // } - // ).then(chart => { - // if (chart.labels.length) { - // this.percentage_chart = new frappe.Chart('.therapy-session-percentage-chart', { - // title: title, - // type: 'percentage', - // data: { - // labels: chart.labels, - // datasets: chart.datasets - // }, - // truncateLegends: 1, - // barOptions: { - // height: 11, - // depth: 1 - // }, - // height: 160, - // maxSlices: 8, - // colors: ['#5e64ff', '#743ee2', '#ff5858', '#ffa00a', '#feef72', '#28a745', '#98d85b', '#a9a7ac'], - // }); - // } else { - // this.wrapper.find('.percentage-chart-container').hide(); - // } - // }); - } - - create_percentage_chart_filters() { - let filters = [ - { - label: 'Therapy Type', - options: ['Therapy Type', 'Exercise Type'], - fieldnames: ['therapy_type', 'exercise_type'], - action: (selected_item, fieldname) => { - let title = selected_item + ' Distribution'; - this.render_percentage_chart(fieldname, title); - } - }, - ]; - frappe.dashboard_utils.render_chart_filters(filters, 'chart-filter', '.percentage-chart-container'); - } - - create_time_span_filters(action_method, parent) { - let chart_control = $(parent).find('.chart-control'); - let filters = [ - { - label: 'Last Month', - options: ['Select Date Range', 'Last Week', 'Last Month', 'Last Quarter', 'Last Year'], - action: (selected_item) => { - if (selected_item === 'Select Date Range') { - this.render_date_range_fields(action_method, chart_control); - } else { - // hide date range field if visible - let date_field = $(parent).find('.date-field'); - if (date_field.is(':visible')) { - date_field.hide(); - } - this[action_method](selected_item); - } - } - } - ]; - frappe.dashboard_utils.render_chart_filters(filters, 'chart-filter', chart_control, 1); - } - - render_date_range_fields(action_method, parent) { - let date_field = $(parent).find('.date-field'); - - if (!date_field.length) { - let date_field_wrapper = $( - `
` - ).appendTo(parent); - - let date_range_field = frappe.ui.form.make_control({ - df: { - fieldtype: 'DateRange', - fieldname: 'from_date', - placeholder: 'Date Range', - input_class: 'input-xs', - reqd: 1, - change: () => { - let selected_date_range = date_range_field.get_value(); - if (selected_date_range && selected_date_range.length === 2) { - this[action_method](selected_date_range); - } - } - }, - parent: date_field_wrapper, - render_input: 1 - }); - } else if (!date_field.is(':visible')) { - date_field.show(); - } - } - - show_therapy_progress() { - let me = this; - let therapy_type = frappe.ui.form.make_control({ - parent: $('.therapy-type-search'), - df: { - fieldtype: 'Link', - options: 'Therapy Type', - fieldname: 'therapy_type', - placeholder: __('Select Therapy Type'), - only_select: true, - change: () => { - if (me.therapy_type != therapy_type.get_value() && therapy_type.get_value()) { - me.therapy_type = therapy_type.get_value(); - me.render_therapy_progress_chart(); - } - } - } - }); - therapy_type.refresh(); - this.create_time_span_filters('render_therapy_progress_chart', '.therapy-progress'); - } - - render_therapy_progress_chart(time_span='Last Month') { - if (!this.therapy_type) return; - - frappe.xcall( - 'erpnext.healthcare.page.patient_progress.patient_progress.get_therapy_progress_data', { - patient: this.patient_id, - therapy_type: this.therapy_type, - time_span: time_span - } - ).then(chart => { - let data = { - labels: chart.labels, - datasets: chart.datasets - } - let parent = '.therapy-progress-line-chart'; - if (!chart.labels.length) { - this.show_null_state(parent); - } else { - if (!this.therapy_line_chart) { - this.therapy_line_chart = new frappe.Chart(parent, { - type: 'axis-mixed', - height: 250, - data: data, - lineOptions: { - regionFill: 1 - }, - axisOptions: { - xIsSeries: 1 - } - }); - } else { - $(parent).find('.chart-container').show(); - $(parent).find('.chart-empty-state').hide(); - this.therapy_line_chart.update(data); - } - } - }); - } - - show_assessment_results() { - let me = this; - let assessment_template = frappe.ui.form.make_control({ - parent: $('.assessment-template-search'), - df: { - fieldtype: 'Link', - options: 'Patient Assessment Template', - fieldname: 'assessment_template', - placeholder: __('Select Assessment Template'), - only_select: true, - change: () => { - if (me.assessment_template != assessment_template.get_value() && assessment_template.get_value()) { - me.assessment_template = assessment_template.get_value(); - me.render_assessment_result_chart(); - } - } - } - }); - assessment_template.refresh(); - this.create_time_span_filters('render_assessment_result_chart', '.assessment-results'); - } - - render_assessment_result_chart(time_span='Last Month') { - if (!this.assessment_template) return; - - frappe.xcall( - 'erpnext.healthcare.page.patient_progress.patient_progress.get_patient_assessment_data', { - patient: this.patient_id, - assessment_template: this.assessment_template, - time_span: time_span - } - ).then(chart => { - let data = { - labels: chart.labels, - datasets: chart.datasets, - yMarkers: [ - { label: 'Max Score', value: chart.max_score } - ], - } - let parent = '.assessment-results-line-chart'; - if (!chart.labels.length) { - this.show_null_state(parent); - } else { - if (!this.assessment_line_chart) { - this.assessment_line_chart = new frappe.Chart(parent, { - type: 'axis-mixed', - height: 250, - data: data, - lineOptions: { - regionFill: 1 - }, - axisOptions: { - xIsSeries: 1 - }, - tooltipOptions: { - formatTooltipY: d => __('{0} out of {1}', [d, chart.max_score]) - } - }); - } else { - $(parent).find('.chart-container').show(); - $(parent).find('.chart-empty-state').hide(); - this.assessment_line_chart.update(data); - } - } - }); - } - - show_therapy_assessment_correlation() { - let me = this; - let assessment = frappe.ui.form.make_control({ - parent: $('.assessment-correlation-template-search'), - df: { - fieldtype: 'Link', - options: 'Patient Assessment Template', - fieldname: 'assessment', - placeholder: __('Select Assessment Template'), - only_select: true, - change: () => { - if (me.assessment != assessment.get_value() && assessment.get_value()) { - me.assessment = assessment.get_value(); - me.render_therapy_assessment_correlation_chart(); - } - } - } - }); - assessment.refresh(); - this.create_time_span_filters('render_therapy_assessment_correlation_chart', '.therapy-assessment-correlation'); - } - - render_therapy_assessment_correlation_chart(time_span='Last Month') { - if (!this.assessment) return; - - frappe.xcall( - 'erpnext.healthcare.page.patient_progress.patient_progress.get_therapy_assessment_correlation_data', { - patient: this.patient_id, - assessment_template: this.assessment, - time_span: time_span - } - ).then(chart => { - let data = { - labels: chart.labels, - datasets: chart.datasets, - yMarkers: [ - { label: 'Max Score', value: chart.max_score } - ], - } - let parent = '.therapy-assessment-correlation-chart'; - if (!chart.labels.length) { - this.show_null_state(parent); - } else { - if (!this.correlation_chart) { - this.correlation_chart = new frappe.Chart(parent, { - type: 'axis-mixed', - height: 300, - data: data, - axisOptions: { - xIsSeries: 1 - } - }); - } else { - $(parent).find('.chart-container').show(); - $(parent).find('.chart-empty-state').hide(); - this.correlation_chart.update(data); - } - } - }); - } - - show_assessment_parameter_progress() { - let me = this; - let parameter = frappe.ui.form.make_control({ - parent: $('.assessment-parameter-search'), - df: { - fieldtype: 'Link', - options: 'Patient Assessment Parameter', - fieldname: 'assessment', - placeholder: __('Select Assessment Parameter'), - only_select: true, - change: () => { - if (me.parameter != parameter.get_value() && parameter.get_value()) { - me.parameter = parameter.get_value(); - me.render_assessment_parameter_progress_chart(); - } - } - } - }); - parameter.refresh(); - this.create_time_span_filters('render_assessment_parameter_progress_chart', '.assessment-parameter-progress'); - } - - render_assessment_parameter_progress_chart(time_span='Last Month') { - if (!this.parameter) return; - - frappe.xcall( - 'erpnext.healthcare.page.patient_progress.patient_progress.get_assessment_parameter_data', { - patient: this.patient_id, - parameter: this.parameter, - time_span: time_span - } - ).then(chart => { - let data = { - labels: chart.labels, - datasets: chart.datasets - } - let parent = '.assessment-parameter-progress-chart'; - if (!chart.labels.length) { - this.show_null_state(parent); - } else { - if (!this.parameter_chart) { - this.parameter_chart = new frappe.Chart(parent, { - type: 'line', - height: 250, - data: data, - lineOptions: { - regionFill: 1 - }, - axisOptions: { - xIsSeries: 1 - }, - tooltipOptions: { - formatTooltipY: d => d + '%' - } - }); - } else { - $(parent).find('.chart-container').show(); - $(parent).find('.chart-empty-state').hide(); - this.parameter_chart.update(data); - } - } - }); - } - - show_null_state(parent) { - let null_state = $(parent).find('.chart-empty-state'); - if (null_state.length) { - $(null_state).show(); - } else { - null_state = $( - `
${__( - "No Data..." - )}
` - ); - $(parent).append(null_state); - } - $(parent).find('.chart-container').hide(); - } -} diff --git a/erpnext/healthcare/page/patient_progress/patient_progress.json b/erpnext/healthcare/page/patient_progress/patient_progress.json deleted file mode 100644 index 0175cb9c457..00000000000 --- a/erpnext/healthcare/page/patient_progress/patient_progress.json +++ /dev/null @@ -1,33 +0,0 @@ -{ - "content": null, - "creation": "2020-06-12 15:46:23.111928", - "docstatus": 0, - "doctype": "Page", - "idx": 0, - "modified": "2020-07-23 21:45:45.540055", - "modified_by": "Administrator", - "module": "Healthcare", - "name": "patient-progress", - "owner": "Administrator", - "page_name": "patient-progress", - "restrict_to_domain": "Healthcare", - "roles": [ - { - "role": "Healthcare Administrator" - }, - { - "role": "Physician" - }, - { - "role": "Patient" - }, - { - "role": "System Manager" - } - ], - "script": null, - "standard": "Yes", - "style": null, - "system_page": 0, - "title": "Patient Progress" -} \ No newline at end of file diff --git a/erpnext/healthcare/page/patient_progress/patient_progress.py b/erpnext/healthcare/page/patient_progress/patient_progress.py deleted file mode 100644 index c17f10574a9..00000000000 --- a/erpnext/healthcare/page/patient_progress/patient_progress.py +++ /dev/null @@ -1,198 +0,0 @@ -import json -from datetime import datetime - -import frappe -from frappe import _ -from frappe.utils import get_timespan_date_range, getdate - - -@frappe.whitelist() -def get_therapy_sessions_count(patient): - total = frappe.db.count('Therapy Session', filters={ - 'docstatus': 1, - 'patient': patient - }) - - month_start = datetime.today().replace(day=1) - this_month = frappe.db.count('Therapy Session', filters={ - 'creation': ['>', month_start], - 'docstatus': 1, - 'patient': patient - }) - - return { - 'total_therapy_sessions': total, - 'therapy_sessions_this_month': this_month - } - - -@frappe.whitelist() -def get_patient_heatmap_data(patient, date): - return dict(frappe.db.sql(""" - SELECT - unix_timestamp(communication_date), count(*) - FROM - `tabPatient Medical Record` - WHERE - communication_date > subdate(%(date)s, interval 1 year) and - communication_date < subdate(%(date)s, interval -1 year) and - patient = %(patient)s - GROUP BY communication_date - ORDER BY communication_date asc""", {'date': date, 'patient': patient})) - - -@frappe.whitelist() -def get_therapy_sessions_distribution_data(patient, field): - if field == 'therapy_type': - result = frappe.db.get_all('Therapy Session', - filters = {'patient': patient, 'docstatus': 1}, - group_by = field, - order_by = field, - fields = [field, 'count(*)'], - as_list = True) - - elif field == 'exercise_type': - data = frappe.db.get_all('Therapy Session', filters={ - 'docstatus': 1, - 'patient': patient - }, as_list=True) - therapy_sessions = [entry[0] for entry in data] - - result = frappe.db.get_all('Exercise', - filters = { - 'parenttype': 'Therapy Session', - 'parent': ['in', therapy_sessions], - 'docstatus': 1 - }, - group_by = field, - order_by = field, - fields = [field, 'count(*)'], - as_list = True) - - return { - 'labels': [r[0] for r in result if r[0] != None], - 'datasets': [{ - 'values': [r[1] for r in result] - }] - } - - -@frappe.whitelist() -def get_therapy_progress_data(patient, therapy_type, time_span): - date_range = get_date_range(time_span) - query_values = {'from_date': date_range[0], 'to_date': date_range[1], 'therapy_type': therapy_type, 'patient': patient} - result = frappe.db.sql(""" - SELECT - start_date, total_counts_targeted, total_counts_completed - FROM - `tabTherapy Session` - WHERE - start_date BETWEEN %(from_date)s AND %(to_date)s and - docstatus = 1 and - therapy_type = %(therapy_type)s and - patient = %(patient)s - ORDER BY start_date""", query_values, as_list=1) - - return { - 'labels': [r[0] for r in result if r[0] != None], - 'datasets': [ - { 'name': _('Targetted'), 'values': [r[1] for r in result if r[0] != None] }, - { 'name': _('Completed'), 'values': [r[2] for r in result if r[0] != None] } - ] - } - -@frappe.whitelist() -def get_patient_assessment_data(patient, assessment_template, time_span): - date_range = get_date_range(time_span) - query_values = {'from_date': date_range[0], 'to_date': date_range[1], 'assessment_template': assessment_template, 'patient': patient} - result = frappe.db.sql(""" - SELECT - assessment_datetime, total_score, total_score_obtained - FROM - `tabPatient Assessment` - WHERE - DATE(assessment_datetime) BETWEEN %(from_date)s AND %(to_date)s and - docstatus = 1 and - assessment_template = %(assessment_template)s and - patient = %(patient)s - ORDER BY assessment_datetime""", query_values, as_list=1) - - return { - 'labels': [getdate(r[0]) for r in result if r[0] != None], - 'datasets': [ - { 'name': _('Score Obtained'), 'values': [r[2] for r in result if r[0] != None] } - ], - 'max_score': result[0][1] if result else None - } - -@frappe.whitelist() -def get_therapy_assessment_correlation_data(patient, assessment_template, time_span): - date_range = get_date_range(time_span) - query_values = {'from_date': date_range[0], 'to_date': date_range[1], 'assessment': assessment_template, 'patient': patient} - result = frappe.db.sql(""" - SELECT - therapy.therapy_type, count(*), avg(assessment.total_score_obtained), total_score - FROM - `tabPatient Assessment` assessment INNER JOIN `tabTherapy Session` therapy - ON - assessment.therapy_session = therapy.name - WHERE - DATE(assessment.assessment_datetime) BETWEEN %(from_date)s AND %(to_date)s and - assessment.docstatus = 1 and - assessment.patient = %(patient)s and - assessment.assessment_template = %(assessment)s - GROUP BY therapy.therapy_type - """, query_values, as_list=1) - - return { - 'labels': [r[0] for r in result if r[0] != None], - 'datasets': [ - { 'name': _('Sessions'), 'chartType': 'bar', 'values': [r[1] for r in result if r[0] != None] }, - { 'name': _('Average Score'), 'chartType': 'line', 'values': [round(r[2], 2) for r in result if r[0] != None] } - ], - 'max_score': result[0][1] if result else None - } - -@frappe.whitelist() -def get_assessment_parameter_data(patient, parameter, time_span): - date_range = get_date_range(time_span) - query_values = {'from_date': date_range[0], 'to_date': date_range[1], 'parameter': parameter, 'patient': patient} - results = frappe.db.sql(""" - SELECT - assessment.assessment_datetime, - sheet.score, - template.scale_max - FROM - `tabPatient Assessment Sheet` sheet - INNER JOIN `tabPatient Assessment` assessment - ON sheet.parent = assessment.name - INNER JOIN `tabPatient Assessment Template` template - ON template.name = assessment.assessment_template - WHERE - DATE(assessment.assessment_datetime) BETWEEN %(from_date)s AND %(to_date)s and - assessment.docstatus = 1 and - sheet.parameter = %(parameter)s and - assessment.patient = %(patient)s - ORDER BY - assessment.assessment_datetime asc - """, query_values, as_list=1) - - score_percentages = [] - for r in results: - if r[2] != 0 and r[0] != None: - score = round((int(r[1]) / int(r[2])) * 100, 2) - score_percentages.append(score) - - return { - 'labels': [getdate(r[0]) for r in results if r[0] != None], - 'datasets': [ - { 'name': _('Score'), 'values': score_percentages } - ] - } - -def get_date_range(time_span): - try: - time_span = json.loads(time_span) - return time_span - except json.decoder.JSONDecodeError: - return get_timespan_date_range(time_span.lower()) diff --git a/erpnext/healthcare/page/patient_progress/patient_progress_sidebar.html b/erpnext/healthcare/page/patient_progress/patient_progress_sidebar.html deleted file mode 100644 index 4ee65738ba3..00000000000 --- a/erpnext/healthcare/page/patient_progress/patient_progress_sidebar.html +++ /dev/null @@ -1,29 +0,0 @@ -
-
- {% if patient_image %} -
- {% endif %} -
-
- {% if patient_name %} -

{{patient_name}}

- {% endif %} - {% if patient_gender %} -

{%=__("Gender: ") %} {{patient_gender}}

- {% endif %} - {% if patient_mobile %} -

{%=__("Contact: ") %} {{patient_mobile}}

- {% endif %} - {% if total_therapy_sessions %} -

{%=__("Total Therapy Sessions: ") %} {{total_therapy_sessions}}

- {% endif %} - {% if therapy_sessions_this_month %} -

{%=__("Monthly Therapy Sessions: ") %} {{therapy_sessions_this_month}}

- {% endif %} -
- -
diff --git a/erpnext/healthcare/print_format/__init__.py b/erpnext/healthcare/print_format/__init__.py deleted file mode 100644 index e69de29bb2d..00000000000 diff --git a/erpnext/healthcare/print_format/encounter_print/__init__.py b/erpnext/healthcare/print_format/encounter_print/__init__.py deleted file mode 100644 index e69de29bb2d..00000000000 diff --git a/erpnext/healthcare/print_format/encounter_print/encounter_print.json b/erpnext/healthcare/print_format/encounter_print/encounter_print.json deleted file mode 100644 index 3c90adb0a1c..00000000000 --- a/erpnext/healthcare/print_format/encounter_print/encounter_print.json +++ /dev/null @@ -1,22 +0,0 @@ -{ - "align_labels_right": 0, - "creation": "2017-04-10 14:05:53.355863", - "custom_format": 1, - "disabled": 0, - "doc_type": "Patient Encounter", - "docstatus": 0, - "doctype": "Print Format", - "font": "Default", - "html": "
\n {% if letter_head and not no_letterhead -%}\n
{{ letter_head }}
\n
\n {% else %}\n
\n

{{doc.name}}

\n
\n {%- endif %}\n
\n
\n {% if doc.appointment %}\n\t
\n\t\t\t
\n\t\t\t\n\t\t\t
\n\t\t\t
\n\t\t\t: {{doc.appointment}}\n\t\t\t
\n\t\t
\n\t\t{%- endif -%}\n\n
\n\t\t
\n\t\t\t \n\t\t
\n {% if doc.patient %}\n\t\t
\n\t\t\t : {{doc.patient}}\n\t\t
\n {% else %}\n
\n\t\t\t : Patient Name\n\t\t
\n {%- endif -%}\n\t\t
\n\t
\n\t\t\t
\n\t\t\t\t\n\t\t\t
\n\t\t\t
\n\t\t\t : {{doc.patient_age}}\n\t\t\t
\n\t\t
\n\n
\n
\n\t\t\t\t\n\t\t\t
\n\t\t\t
\n\t\t\t : {{doc.patient_sex}}\n\t\t\t
\n
\n\n
\n
\n\n
\n\t
\n\t\t \n\t
\n {% if doc.practitioner %}\n\t
\n\t\t\t: {{doc.practitioner}}\n\t
\n {%- endif -%}\n\t
\n\n {% if doc.encounter_date %}\n\t
\n\t\t
\n\t\t\n\t\t
\n\t\t
\n\t\t: {{doc.encounter_date}}\n\t\t
\n
\n\t {%- endif -%}\n {% if doc.encounter_time %}\n\t
\n\t\t
\n\t\t\n\t\t
\n\t\t
\n\t\t: {{doc.encounter_time}}\n\t\t
\n
\n\t {%- endif -%}\n {% if doc.medical_department %}\n\t
\n\t\t
\n\t\t\n\t\t
\n\t\t
\n\t\t: {{doc.visit_department}}\n\t\t
\n
\n {%- endif -%}\n
\n\n
\n\n
\n
\n
\n {% if doc.symptoms_in_print%}\n {% if doc.symptoms %}\n Complaints:\n {{doc.symptoms}}\n \t
\n {%- endif -%}\n {%- endif -%}\n\n {% if doc.diagnosis_in_print%}\n {% if doc.diagnosis %}\n \t Diagnosis:\n {{doc.diagnosis}}\n
\n {%- endif -%}\n {%- endif -%}\n\n
\n\n
\n {% if doc.drug_prescription %}\n
\n Rx,\n \n \n \n\n {%- for row in doc.drug_prescription -%}\n \n \n \t\n \t\n \n \n\t {%- endfor -%}\n \n
\n {%- if row.drug_name -%}{{ row.drug_name }}{%- endif -%}\n \n {%- if row.dosage -%}{{ row.dosage }}{%- endif -%}\n \n {%- if row.period -%}{{ row.period }}{%- endif -%}\n\t\t \n\t\t\t
\n {%- if row.comment -%}{{ row.comment }}{%- endif -%}\n
\n\t\t
\n\n\n {%- endif -%}\n
\n\n\n
\n {% if doc.lab_test_prescription %}\n Investigations,\n \n \n \n\n {%- for row in doc.lab_test_prescription -%}\n \n \n \n \n\n\t {%- endfor -%}\n \n
\n {%- if row.lab_test_name -%}{{ row.lab_test_name }}{%- endif -%}\n \n\t\t\t
\n {%- if row.lab_test_comment -%}{{ row.lab_test_comment }}{%- endif -%}\n
\n\t\t
\n\n\n {%- endif -%}\n
\n
\n {% if doc.encounter_comment %}\n
\n {{doc.encounter_comment}}\n {%- endif -%}\n
\n", - "idx": 0, - "line_breaks": 0, - "modified": "2018-09-04 11:52:54.473702", - "modified_by": "Administrator", - "module": "Healthcare", - "name": "Encounter Print", - "owner": "Administrator", - "print_format_builder": 0, - "print_format_type": "Jinja", - "show_section_headings": 0, - "standard": "Yes" -} \ No newline at end of file diff --git a/erpnext/healthcare/print_format/lab_test_print/__init__.py b/erpnext/healthcare/print_format/lab_test_print/__init__.py deleted file mode 100644 index e69de29bb2d..00000000000 diff --git a/erpnext/healthcare/print_format/lab_test_print/lab_test_print.json b/erpnext/healthcare/print_format/lab_test_print/lab_test_print.json deleted file mode 100644 index f7d16769c66..00000000000 --- a/erpnext/healthcare/print_format/lab_test_print/lab_test_print.json +++ /dev/null @@ -1,23 +0,0 @@ -{ - "align_labels_right": 0, - "creation": "2017-04-24 15:38:45.332473", - "custom_format": 1, - "disabled": 0, - "doc_type": "Lab Test", - "docstatus": 0, - "doctype": "Print Format", - "font": "Default", - "html": "
\n {% if letter_head and not no_letterhead -%}\n
{{ letter_head }}
\n
\n {%- endif %}\n\n {% if (doc.docstatus != 1) %}\n

WORKSHEET

\n\t
\n\t
\n
\n\n
\n
\n \n
\n {% if doc.patient_name %}\n
\n {{ doc.patient_name }}\n
\n {% else %}\n
\n {{ doc.patient }}\n
\n {%- endif -%}\n
\n\n
\n
\n \n
\n
\n {{ doc.patient_age or '' }}\n
\n
\n\n
\n
\n \n
\n
\n {{ doc.patient_sex or '' }}\n
\n
\n\n
\n\n
\n\n
\n
\n \n
\n {% if doc.practitioner_name %}\n
\n {{ doc.practitioner_name }}\n
\n {% else %}\n\t\t\t{% if doc.referring_practitioner_name %}\n
\n {{ doc.referring_practitioner_name }}\n
\n\t\t {% endif %}\n {%- endif -%}\n
\n\n {% if doc.sample_date %}\n
\n
\n \n
\n
\n {{ doc.sample_date }}\n
\n
\n {%- endif -%}\n
\n
\n\n\t
\n

Department of {{ doc.department }}

\n
\n\n\t\n \n {%- if doc.normal_test_items -%}\n \n \n \n \n \n\n {%- if doc.normal_test_items|length > 1 %}\n \n {%- endif -%}\n\n {%- for row in doc.normal_test_items -%}\n \n \n\n \n\n \n \n\n {%- endfor -%}\n {%- endif -%}\n \n
Name of TestResultNormal Range
{{ doc.lab_test_name }}
\n {%- if doc.normal_test_items|length > 1 %}  {%- endif -%}\n {%- if row.lab_test_name -%}{{ row.lab_test_name }}\n {%- else -%}   {%- endif -%}\n {%- if row.lab_test_event -%}   {{ row.lab_test_event }}{%- endif -%}\n \n {%- if row.lab_test_uom -%} {{ row.lab_test_uom }}{%- endif -%}\n \n
\n {%- if row.normal_range -%}{{ row.normal_range }}{%- endif -%}\n
\n
\n\n\t\n \n {%- if doc.descriptive_test_items -%}\n \n \n \n \n \n\t\t\t{% set gr_lab_test_name = {'ltname': ''} %}\n {%- for row in doc.descriptive_test_items -%}\n\t\t\t{%- if row.lab_test_name -%}\n\t\t\t{%- if row.lab_test_name != gr_lab_test_name.ltname -%}\n\t\t\t\n\t\t\t\t\n\t\t\t\t\n\t\t\t\n\t\t\t{% if gr_lab_test_name.update({'ltname': row.lab_test_name}) %} {% endif %}\n\t\t\t{%- endif -%}\n\t\t\t{%- endif -%}\n \n \n \n \n {%- endfor -%}\n {%- endif -%}\n \n
Name of TestResult
{{ doc.lab_test_name }}
 {{ row.lab_test_name }}
  {{ row.lab_test_particulars }}
\n
\n {% if doc.worksheet_instructions %}\n
\n Instructions\n {{ doc.worksheet_instructions }}\n {%- endif -%}\n
\n {% elif (frappe.db.get_value(\"Healthcare Settings\", \"None\", \"require_test_result_approval\") == '1' and doc.status != \"Approved\") %}\n Lab Tests have to be Approved for Print .. !\n {%- else -%}\n
\n
\n\n
\n
\n \n
\n {% if doc.patient_name %}\n
\n {{ doc.patient_name }}\n
\n {% else %}\n
\n {{ doc.patient }}\n
\n {%- endif -%}\n
\n\n
\n
\n \n
\n
\n {{ doc.patient_age or '' }}\n
\n
\n\n
\n
\n \n
\n
\n {{ doc.patient_sex or '' }}\n
\n
\n\n
\n\n
\n\n
\n
\n \n
\n {% if doc.practitioner_name %}\n
\n {{ doc.practitioner_name }}\n
\n\t\t{% else %}\n\t\t {% if doc.referring_practitioner_name %}\n
\n {{ doc.referring_practitioner_name }}\n
\n\t\t\t{% endif %}\n {%- endif -%}\n
\n\n {% if doc.sample_date %}\n
\n
\n \n
\n
\n {{ doc.sample_date }}\n
\n
\n {%- endif -%}\n\n {% if doc.result_date %}\n
\n
\n \n
\n
\n {{ doc.result_date }}\n
\n
\n {%- endif -%}\n\n
\n\n
\n\n
\n

Department of {{ doc.department }}

\n
\n\n\t
\n\t\t{% if doc.result_legend and (doc.legend_print_position == \"Top\" or doc.legend_print_position == \"Both\")%}\n\t\tResult Legend:\n\t\t{{ doc.result_legend }}\n\t\t{%- endif -%}\n\t
\n\n \n \n {%- if doc.normal_test_items -%}\n \n \n \n \n \n\n {%- if doc.normal_test_items|length > 1 %}\n \n {%- endif -%}\n\n {%- for row in doc.normal_test_items -%}\n \n \n\n \n\n \n \n\n {%- endfor -%}\n {%- endif -%}\n \n
Name of TestResultNormal Range
{{ doc.lab_test_name }}
\n {%- if doc.normal_test_items|length > 1 %}  {%- endif -%}\n {%- if row.lab_test_name -%}{{ row.lab_test_name }}\n {%- else -%}   {%- endif -%}\n {%- if row.lab_test_event -%}   {{ row.lab_test_event }}{%- endif -%}\n \n\t\t\t\t\t{%- if row.result_value -%}\n\t\t\t\t\t\t{%- if row.bold -%}{% endif %}\n\t\t\t\t\t\t{%- if row.underline -%}{% endif %}\n\t\t\t\t\t\t{%- if row.italic -%}{% endif %}\n {{ row.result_value }}\n {%- if row.lab_test_uom -%} {{ row.lab_test_uom }}{%- endif -%}\n\t\t\t\t\t\t{%- if row.italic -%}{% endif %}\n\t\t\t\t\t\t{%- if row.underline -%}{% endif %}\n\t\t\t\t\t\t{%- if row.bold -%}{% endif %}\n\t\t\t\t\t{%- endif -%}\n \n\t\t\t\t\t{%- if row.secondary_uom and row.conversion_factor and row.secondary_uom_result -%}\n\t\t\t\t\t\t
\n\t\t\t\t\t\t{%- if row.bold -%}{% endif %}\n\t\t\t\t\t\t{%- if row.underline -%}{% endif %}\n\t\t\t\t\t\t{%- if row.italic -%}{% endif %}\n {{ row.secondary_uom_result }}\n  {{ row.secondary_uom }}\n\t\t\t\t\t\t{%- if row.italic -%}{% endif %}\n\t\t\t\t\t\t{%- if row.underline -%}{% endif %}\n\t\t\t\t\t\t{%- if row.bold -%}{% endif %}\n\t\t\t\t\t\t \n\t\t\t\t\t{%- endif -%}\n
\n
\n {%- if row.normal_range -%}{{ row.normal_range }}{%- endif -%}\n
\n
\n\n \n \n {%- if doc.descriptive_test_items -%}\n \n \n \n \n \n\t\t\t{% set gr_lab_test_name = {'ltname': ''} %}\n {%- for row in doc.descriptive_test_items -%}\n\t\t\t{%- if row.lab_test_name -%}\n\t\t\t{%- if row.lab_test_name != gr_lab_test_name.ltname -%}\n\t\t\t\n\t\t\t\t\n\t\t\t\t\n\t\t\t\n\t\t\t{% if gr_lab_test_name.update({'ltname': row.lab_test_name}) %} {% endif %}\n\t\t\t{%- endif -%}\n\t\t\t{%- endif -%}\n \n \n \n \n {%- endfor -%}\n {%- endif -%}\n\n\t\t\t{%- if doc.organisms -%}\n\t\t\t\n\t\t\t\t\n\t\t\t\t\n\t\t\t\n\t\t\t{%- for row in doc.organisms -%}\n\t\t\t\n\t\t\t\t\n\t\t\t\t\n\t\t\t\n\t\t\t{%- endfor -%}\n\t\t\t{%- endif -%}\n\n\t\t\t{%- if doc.sensitivity_test_items -%}\n\t\t\t\n\t\t\t\t\n\t\t\t\t\n\t\t\t\n\t\t\t{%- for row in doc.sensitivity_test_items -%}\n\t\t\t\n\t\t\t\t\n\t\t\t\t\n\t\t\t\n\t\t\t{%- endfor -%}\n\t\t\t{%- endif -%}\n\n \n
Name of TestResult
{{ doc.lab_test_name }}
 {{ row.lab_test_name }}
  {{ row.lab_test_particulars }} \n {%- if row.result_value -%}{{ row.result_value }}{%- endif -%}\n
OrganismColony Population
{{ row.organism }} \n\t\t\t\t\t{{ row.colony_population }}\n\t\t\t\t\t{% if row.colony_uom %}\n\t\t\t\t\t\t{{ row.colony_uom }}\n\t\t\t\t\t{% endif %}\n\t\t\t\t
AntibioticSensitivity
{{ row.antibiotic }} {{ row.antibiotic_sensitivity }}
\n
\n {% if doc.custom_result %}\n
\n
{{ doc.custom_result }}
\n {%- endif -%}\n
\n\n
\n {% if doc.lab_test_comment %}\n
\n Comments\n {{ doc.lab_test_comment }}\n {%- endif -%}\n
\n\n
\n {%- if (frappe.db.get_value(\"Healthcare Settings\", \"None\", \"employee_name_and_designation_in_print\") == '1') -%}\n {%- if doc.employee_name -%}\n
{{ doc.employee_name }}
\n {%- endif -%}\n {%- if doc.employee_designation -%}\n
{{ doc.employee_designation }}
\n {%- endif -%}\n {%- else -%}\n {%- if frappe.db.get_value(\"Healthcare Settings\", \"None\", \"custom_signature_in_print\") -%}\n
{{ frappe.db.get_value(\"Healthcare Settings\", \"None\", \"custom_signature_in_print\") }}
\n {%- endif -%}\n {%- endif -%}\n
\n\n
\n {% if doc.result_legend and (doc.legend_print_position == \"Bottom\" or doc.legend_print_position == \"Both\" or doc.legend_print_position == \"\")%}\n
\n Result Legend\n {{ doc.result_legend }}\n {%- endif -%}\n
\n {%- endif -%}\n
", - "idx": 0, - "line_breaks": 0, - "modified": "2020-07-08 15:34:28.866798", - "modified_by": "Administrator", - "module": "Healthcare", - "name": "Lab Test Print", - "owner": "Administrator", - "print_format_builder": 0, - "print_format_type": "Jinja", - "raw_printing": 0, - "show_section_headings": 0, - "standard": "Yes" -} \ No newline at end of file diff --git a/erpnext/healthcare/print_format/sample_id_print/__init__.py b/erpnext/healthcare/print_format/sample_id_print/__init__.py deleted file mode 100644 index e69de29bb2d..00000000000 diff --git a/erpnext/healthcare/print_format/sample_id_print/sample_id_print.json b/erpnext/healthcare/print_format/sample_id_print/sample_id_print.json deleted file mode 100644 index 4819e6d57ac..00000000000 --- a/erpnext/healthcare/print_format/sample_id_print/sample_id_print.json +++ /dev/null @@ -1,22 +0,0 @@ -{ - "align_labels_left": 0, - "creation": "2017-02-17 17:40:52.967840", - "custom_format": 1, - "disabled": 0, - "doc_type": "Sample Collection", - "docstatus": 0, - "doctype": "Print Format", - "font": "Default", - "html": "\n{% set column = 0 %}\n\n{% for _ in range(0, doc.num_print) %}\n{% if column == 0 -%}{% endif %}\n\t\n{% if column == 0 %}{% set column = column+1 %}\n{% elif column == 2%} {%- set column = 0 %}\n{% else %}{%- set column = column+1 -%}{%- endif %}\n\t\n{% endfor %}\n
{{doc.name}}
{{doc.patient}}
\n{% if doc.patient_age %}{{doc.patient_age}}, {% endif %} {% if doc.patient_sex %}{{doc.patient_sex}}{% endif %}
{% if doc.collected_time %}{{doc.collected_time}} {% endif %}
{% if doc.collected_by %} {{doc.collected_by}} {% endif %}
", - "idx": 0, - "line_breaks": 0, - "modified": "2017-03-30 18:09:39.537609", - "modified_by": "Administrator", - "module": "Healthcare", - "name": "Sample ID Print", - "owner": "Administrator", - "print_format_builder": 0, - "print_format_type": "Jinja", - "show_section_headings": 0, - "standard": "Yes" -} diff --git a/erpnext/healthcare/report/__init__.py b/erpnext/healthcare/report/__init__.py deleted file mode 100644 index e69de29bb2d..00000000000 diff --git a/erpnext/healthcare/report/inpatient_medication_orders/__init__.py b/erpnext/healthcare/report/inpatient_medication_orders/__init__.py deleted file mode 100644 index e69de29bb2d..00000000000 diff --git a/erpnext/healthcare/report/inpatient_medication_orders/inpatient_medication_orders.js b/erpnext/healthcare/report/inpatient_medication_orders/inpatient_medication_orders.js deleted file mode 100644 index a10f83760fa..00000000000 --- a/erpnext/healthcare/report/inpatient_medication_orders/inpatient_medication_orders.js +++ /dev/null @@ -1,57 +0,0 @@ -// Copyright (c) 2016, Frappe Technologies Pvt. Ltd. and contributors -// For license information, please see license.txt -/* eslint-disable */ - -frappe.query_reports["Inpatient Medication Orders"] = { - "filters": [ - { - fieldname: "company", - label: __("Company"), - fieldtype: "Link", - options: "Company", - default: frappe.defaults.get_user_default("Company"), - reqd: 1 - }, - { - fieldname: "from_date", - label: __("From Date"), - fieldtype: "Date", - default: frappe.datetime.add_months(frappe.datetime.get_today(), -1), - reqd: 1 - }, - { - fieldname: "to_date", - label: __("To Date"), - fieldtype: "Date", - default: frappe.datetime.now_date(), - reqd: 1 - }, - { - fieldname: "patient", - label: __("Patient"), - fieldtype: "Link", - options: "Patient" - }, - { - fieldname: "service_unit", - label: __("Healthcare Service Unit"), - fieldtype: "Link", - options: "Healthcare Service Unit", - get_query: () => { - var company = frappe.query_report.get_filter_value('company'); - return { - filters: { - 'company': company, - 'is_group': 0 - } - } - } - }, - { - fieldname: "show_completed_orders", - label: __("Show Completed Orders"), - fieldtype: "Check", - default: 1 - } - ] -}; diff --git a/erpnext/healthcare/report/inpatient_medication_orders/inpatient_medication_orders.json b/erpnext/healthcare/report/inpatient_medication_orders/inpatient_medication_orders.json deleted file mode 100644 index 9217fa18919..00000000000 --- a/erpnext/healthcare/report/inpatient_medication_orders/inpatient_medication_orders.json +++ /dev/null @@ -1,36 +0,0 @@ -{ - "add_total_row": 0, - "columns": [], - "creation": "2020-11-23 17:25:58.802949", - "disable_prepared_report": 0, - "disabled": 0, - "docstatus": 0, - "doctype": "Report", - "filters": [], - "idx": 0, - "is_standard": "Yes", - "json": "{}", - "modified": "2020-11-23 19:40:20.227591", - "modified_by": "Administrator", - "module": "Healthcare", - "name": "Inpatient Medication Orders", - "owner": "Administrator", - "prepared_report": 0, - "ref_doctype": "Inpatient Medication Order", - "report_name": "Inpatient Medication Orders", - "report_type": "Script Report", - "roles": [ - { - "role": "System Manager" - }, - { - "role": "Healthcare Administrator" - }, - { - "role": "Nursing User" - }, - { - "role": "Physician" - } - ] -} \ No newline at end of file diff --git a/erpnext/healthcare/report/inpatient_medication_orders/inpatient_medication_orders.py b/erpnext/healthcare/report/inpatient_medication_orders/inpatient_medication_orders.py deleted file mode 100644 index 2e809fb66b0..00000000000 --- a/erpnext/healthcare/report/inpatient_medication_orders/inpatient_medication_orders.py +++ /dev/null @@ -1,203 +0,0 @@ -# Copyright (c) 2013, Frappe Technologies Pvt. Ltd. and contributors -# For license information, please see license.txt - -from __future__ import unicode_literals - -import frappe - -from erpnext.healthcare.doctype.inpatient_medication_entry.inpatient_medication_entry import ( - get_current_healthcare_service_unit, -) - - -def execute(filters=None): - columns = get_columns() - data = get_data(filters) - chart = get_chart_data(data) - - return columns, data, None, chart - -def get_columns(): - return [ - { - "fieldname": "patient", - "fieldtype": "Link", - "label": "Patient", - "options": "Patient", - "width": 200 - }, - { - "fieldname": "healthcare_service_unit", - "fieldtype": "Link", - "label": "Healthcare Service Unit", - "options": "Healthcare Service Unit", - "width": 150 - }, - { - "fieldname": "drug", - "fieldtype": "Link", - "label": "Drug Code", - "options": "Item", - "width": 150 - }, - { - "fieldname": "drug_name", - "fieldtype": "Data", - "label": "Drug Name", - "width": 150 - }, - { - "fieldname": "dosage", - "fieldtype": "Link", - "label": "Dosage", - "options": "Prescription Dosage", - "width": 80 - }, - { - "fieldname": "dosage_form", - "fieldtype": "Link", - "label": "Dosage Form", - "options": "Dosage Form", - "width": 100 - }, - { - "fieldname": "date", - "fieldtype": "Date", - "label": "Date", - "width": 100 - }, - { - "fieldname": "time", - "fieldtype": "Time", - "label": "Time", - "width": 100 - }, - { - "fieldname": "is_completed", - "fieldtype": "Check", - "label": "Is Order Completed", - "width": 100 - }, - { - "fieldname": "healthcare_practitioner", - "fieldtype": "Link", - "label": "Healthcare Practitioner", - "options": "Healthcare Practitioner", - "width": 200 - }, - { - "fieldname": "inpatient_medication_entry", - "fieldtype": "Link", - "label": "Inpatient Medication Entry", - "options": "Inpatient Medication Entry", - "width": 200 - }, - { - "fieldname": "inpatient_record", - "fieldtype": "Link", - "label": "Inpatient Record", - "options": "Inpatient Record", - "width": 200 - } - ] - -def get_data(filters): - conditions, values = get_conditions(filters) - - data = frappe.db.sql(""" - SELECT - parent.patient, parent.inpatient_record, parent.practitioner, - child.drug, child.drug_name, child.dosage, child.dosage_form, - child.date, child.time, child.is_completed, child.name - FROM `tabInpatient Medication Order` parent - INNER JOIN `tabInpatient Medication Order Entry` child - ON child.parent = parent.name - WHERE - parent.docstatus = 1 - {conditions} - ORDER BY date, time - """.format(conditions=conditions), values, as_dict=1) - - data = get_inpatient_details(data, filters.get("service_unit")) - - return data - -def get_conditions(filters): - conditions = "" - values = dict() - - if filters.get("company"): - conditions += " AND parent.company = %(company)s" - values["company"] = filters.get("company") - - if filters.get("from_date") and filters.get("to_date"): - conditions += " AND child.date BETWEEN %(from_date)s and %(to_date)s" - values["from_date"] = filters.get("from_date") - values["to_date"] = filters.get("to_date") - - if filters.get("patient"): - conditions += " AND parent.patient = %(patient)s" - values["patient"] = filters.get("patient") - - if not filters.get("show_completed_orders"): - conditions += " AND child.is_completed = 0" - - return conditions, values - - -def get_inpatient_details(data, service_unit): - service_unit_filtered_data = [] - - for entry in data: - entry["healthcare_service_unit"] = get_current_healthcare_service_unit(entry.inpatient_record) - if entry.is_completed: - entry["inpatient_medication_entry"] = get_inpatient_medication_entry(entry.name) - - if service_unit and entry.healthcare_service_unit and service_unit != entry.healthcare_service_unit: - service_unit_filtered_data.append(entry) - - entry.pop("name", None) - - for entry in service_unit_filtered_data: - data.remove(entry) - - return data - -def get_inpatient_medication_entry(order_entry): - return frappe.db.get_value("Inpatient Medication Entry Detail", {"against_imoe": order_entry}, "parent") - -def get_chart_data(data): - if not data: - return None - - labels = ["Pending", "Completed"] - datasets = [] - - status_wise_data = { - "Pending": 0, - "Completed": 0 - } - - for d in data: - if d.is_completed: - status_wise_data["Completed"] += 1 - else: - status_wise_data["Pending"] += 1 - - datasets.append({ - "name": "Inpatient Medication Order Status", - "values": [status_wise_data.get("Pending"), status_wise_data.get("Completed")] - }) - - chart = { - "data": { - "labels": labels, - "datasets": datasets - }, - "type": "donut", - "height": 300 - } - - chart["fieldtype"] = "Data" - - return chart diff --git a/erpnext/healthcare/report/inpatient_medication_orders/test_inpatient_medication_orders.py b/erpnext/healthcare/report/inpatient_medication_orders/test_inpatient_medication_orders.py deleted file mode 100644 index 7f7bebf514a..00000000000 --- a/erpnext/healthcare/report/inpatient_medication_orders/test_inpatient_medication_orders.py +++ /dev/null @@ -1,146 +0,0 @@ -# Copyright (c) 2018, Frappe Technologies Pvt. Ltd. and Contributors -# License: GNU General Public License v3. See license.txt - -from __future__ import unicode_literals - -import datetime -import unittest - -import frappe -from frappe.utils import getdate, now_datetime - -from erpnext.healthcare.doctype.inpatient_medication_order.test_inpatient_medication_order import ( - create_ipme, - create_ipmo, -) -from erpnext.healthcare.doctype.inpatient_record.inpatient_record import ( - admit_patient, - discharge_patient, - schedule_discharge, -) -from erpnext.healthcare.doctype.inpatient_record.test_inpatient_record import ( - create_inpatient, - create_patient, - get_healthcare_service_unit, - mark_invoiced_inpatient_occupancy, -) -from erpnext.healthcare.report.inpatient_medication_orders.inpatient_medication_orders import ( - execute, -) - - -class TestInpatientMedicationOrders(unittest.TestCase): - @classmethod - def setUpClass(self): - frappe.db.sql("delete from `tabInpatient Medication Order` where company='_Test Company'") - frappe.db.sql("delete from `tabInpatient Medication Entry` where company='_Test Company'") - self.patient = create_patient() - self.ip_record = create_records(self.patient) - - def test_inpatient_medication_orders_report(self): - filters = { - 'company': '_Test Company', - 'from_date': getdate(), - 'to_date': getdate(), - 'patient': '_Test IPD Patient', - 'service_unit': '_Test Service Unit Ip Occupancy - _TC' - } - - report = execute(filters) - - expected_data = [ - { - 'patient': '_Test IPD Patient', - 'inpatient_record': self.ip_record.name, - 'practitioner': None, - 'drug': 'Dextromethorphan', - 'drug_name': 'Dextromethorphan', - 'dosage': 1.0, - 'dosage_form': 'Tablet', - 'date': getdate(), - 'time': datetime.timedelta(seconds=32400), - 'is_completed': 0, - 'healthcare_service_unit': '_Test Service Unit Ip Occupancy - _TC' - }, - { - 'patient': '_Test IPD Patient', - 'inpatient_record': self.ip_record.name, - 'practitioner': None, - 'drug': 'Dextromethorphan', - 'drug_name': 'Dextromethorphan', - 'dosage': 1.0, - 'dosage_form': 'Tablet', - 'date': getdate(), - 'time': datetime.timedelta(seconds=50400), - 'is_completed': 0, - 'healthcare_service_unit': '_Test Service Unit Ip Occupancy - _TC' - }, - { - 'patient': '_Test IPD Patient', - 'inpatient_record': self.ip_record.name, - 'practitioner': None, - 'drug': 'Dextromethorphan', - 'drug_name': 'Dextromethorphan', - 'dosage': 1.0, - 'dosage_form': 'Tablet', - 'date': getdate(), - 'time': datetime.timedelta(seconds=75600), - 'is_completed': 0, - 'healthcare_service_unit': '_Test Service Unit Ip Occupancy - _TC' - } - ] - - self.assertEqual(expected_data, report[1]) - - filters = frappe._dict(from_date=getdate(), to_date=getdate(), from_time='', to_time='') - ipme = create_ipme(filters) - ipme.submit() - - filters = { - 'company': '_Test Company', - 'from_date': getdate(), - 'to_date': getdate(), - 'patient': '_Test IPD Patient', - 'service_unit': '_Test Service Unit Ip Occupancy - _TC', - 'show_completed_orders': 0 - } - - report = execute(filters) - self.assertEqual(len(report[1]), 0) - - def tearDown(self): - if frappe.db.get_value('Patient', self.patient, 'inpatient_record'): - # cleanup - Discharge - schedule_discharge(frappe.as_json({'patient': self.patient})) - self.ip_record.reload() - mark_invoiced_inpatient_occupancy(self.ip_record) - - self.ip_record.reload() - discharge_patient(self.ip_record) - - for entry in frappe.get_all('Inpatient Medication Entry'): - doc = frappe.get_doc('Inpatient Medication Entry', entry.name) - doc.cancel() - doc.delete() - - for entry in frappe.get_all('Inpatient Medication Order'): - doc = frappe.get_doc('Inpatient Medication Order', entry.name) - doc.cancel() - doc.delete() - - -def create_records(patient): - frappe.db.sql("""delete from `tabInpatient Record`""") - - # Admit - ip_record = create_inpatient(patient) - ip_record.expected_length_of_stay = 0 - ip_record.save() - ip_record.reload() - service_unit = get_healthcare_service_unit('_Test Service Unit Ip Occupancy') - admit_patient(ip_record, service_unit, now_datetime()) - - ipmo = create_ipmo(patient) - ipmo.submit() - - return ip_record diff --git a/erpnext/healthcare/report/lab_test_report/__init__.py b/erpnext/healthcare/report/lab_test_report/__init__.py deleted file mode 100644 index e69de29bb2d..00000000000 diff --git a/erpnext/healthcare/report/lab_test_report/lab_test_report.js b/erpnext/healthcare/report/lab_test_report/lab_test_report.js deleted file mode 100644 index 7754e2e1962..00000000000 --- a/erpnext/healthcare/report/lab_test_report/lab_test_report.js +++ /dev/null @@ -1,57 +0,0 @@ -// Copyright (c) 2016, ESS -// License: See license.txt - -frappe.query_reports["Lab Test Report"] = { - "filters": [ - { - "fieldname": "from_date", - "label": __("From Date"), - "fieldtype": "Date", - "default": frappe.datetime.add_months(frappe.datetime.get_today(), -1), - "reqd": 1 - }, - { - "fieldname": "to_date", - "label": __("To Date"), - "fieldtype": "Date", - "default": frappe.datetime.now_date(), - "reqd": 1 - }, - { - "fieldname": "company", - "label": __("Company"), - "fieldtype": "Link", - "default": frappe.defaults.get_default("Company"), - "options": "Company" - }, - { - "fieldname": "template", - "label": __("Lab Test Template"), - "fieldtype": "Link", - "options": "Lab Test Template" - }, - { - "fieldname": "patient", - "label": __("Patient"), - "fieldtype": "Link", - "options": "Patient" - }, - { - "fieldname": "department", - "label": __("Medical Department"), - "fieldtype": "Link", - "options": "Medical Department" - }, - { - "fieldname": "status", - "label": __("Status"), - "fieldtype": "Select", - "options": "\nCompleted\nApproved\nRejected" - }, - { - "fieldname": "invoiced", - "label": __("Invoiced"), - "fieldtype": "Check" - } - ] -}; diff --git a/erpnext/healthcare/report/lab_test_report/lab_test_report.json b/erpnext/healthcare/report/lab_test_report/lab_test_report.json deleted file mode 100644 index aeb42897b8a..00000000000 --- a/erpnext/healthcare/report/lab_test_report/lab_test_report.json +++ /dev/null @@ -1,33 +0,0 @@ -{ - "add_total_row": 0, - "creation": "2013-04-23 18:15:29", - "disable_prepared_report": 0, - "disabled": 0, - "docstatus": 0, - "doctype": "Report", - "idx": 1, - "is_standard": "Yes", - "modified": "2020-07-30 18:53:20.102873", - "modified_by": "Administrator", - "module": "Healthcare", - "name": "Lab Test Report", - "owner": "Administrator", - "prepared_report": 0, - "ref_doctype": "Lab Test", - "report_name": "Lab Test Report", - "report_type": "Script Report", - "roles": [ - { - "role": "Laboratory User" - }, - { - "role": "Nursing User" - }, - { - "role": "LabTest Approver" - }, - { - "role": "Healthcare Administrator" - } - ] -} \ No newline at end of file diff --git a/erpnext/healthcare/report/lab_test_report/lab_test_report.py b/erpnext/healthcare/report/lab_test_report/lab_test_report.py deleted file mode 100644 index e2a53bb1e46..00000000000 --- a/erpnext/healthcare/report/lab_test_report/lab_test_report.py +++ /dev/null @@ -1,213 +0,0 @@ -# Copyright (c) 2016, ESS -# License: See license.txt - -from __future__ import unicode_literals - -import frappe -from frappe import _, msgprint - - -def execute(filters=None): - if not filters: filters = {} - - data, columns = [], [] - - columns = get_columns() - lab_test_list = get_lab_tests(filters) - - if not lab_test_list: - msgprint(_('No records found')) - return columns, lab_test_list - - data = [] - for lab_test in lab_test_list: - row = frappe._dict({ - 'test': lab_test.name, - 'template': lab_test.template, - 'company': lab_test.company, - 'patient': lab_test.patient, - 'patient_name': lab_test.patient_name, - 'practitioner': lab_test.practitioner, - 'employee': lab_test.employee, - 'status': lab_test.status, - 'invoiced': lab_test.invoiced, - 'result_date': lab_test.result_date, - 'department': lab_test.department - }) - data.append(row) - - chart = get_chart_data(data) - report_summary = get_report_summary(data) - return columns, data, None, chart, report_summary - - -def get_columns(): - return [ - { - 'fieldname': 'test', - 'label': _('Lab Test'), - 'fieldtype': 'Link', - 'options': 'Lab Test', - 'width': '120' - }, - { - 'fieldname': 'template', - 'label': _('Lab Test Template'), - 'fieldtype': 'Link', - 'options': 'Lab Test Template', - 'width': '120' - }, - { - 'fieldname': 'company', - 'label': _('Company'), - 'fieldtype': 'Link', - 'options': 'Company', - 'width': '120' - }, - { - 'fieldname': 'patient', - 'label': _('Patient'), - 'fieldtype': 'Link', - 'options': 'Patient', - 'width': '120' - }, - { - 'fieldname': 'patient_name', - 'label': _('Patient Name'), - 'fieldtype': 'Data', - 'width': '120' - }, - { - 'fieldname': 'employee', - 'label': _('Lab Technician'), - 'fieldtype': 'Link', - 'options': 'Employee', - 'width': '120' - }, - { - 'fieldname': 'status', - 'label': _('Status'), - 'fieldtype': 'Data', - 'width': '100' - }, - { - 'fieldname': 'invoiced', - 'label': _('Invoiced'), - 'fieldtype': 'Check', - 'width': '100' - }, - { - 'fieldname': 'result_date', - 'label': _('Result Date'), - 'fieldtype': 'Date', - 'width': '100' - }, - { - 'fieldname': 'practitioner', - 'label': _('Requesting Practitioner'), - 'fieldtype': 'Link', - 'options': 'Healthcare Practitioner', - 'width': '120' - }, - { - 'fieldname': 'department', - 'label': _('Medical Department'), - 'fieldtype': 'Link', - 'options': 'Medical Department', - 'width': '100' - } - ] - -def get_lab_tests(filters): - conditions = get_conditions(filters) - data = frappe.get_all( - doctype='Lab Test', - fields=['name', 'template', 'company', 'patient', 'patient_name', 'practitioner', 'employee', 'status', 'invoiced', 'result_date', 'department'], - filters=conditions, - order_by='submitted_date desc' - ) - return data - -def get_conditions(filters): - conditions = { - 'docstatus': ('=', 1) - } - - if filters.get('from_date') and filters.get('to_date'): - conditions['result_date'] = ('between', (filters.get('from_date'), filters.get('to_date'))) - filters.pop('from_date') - filters.pop('to_date') - - for key, value in filters.items(): - if filters.get(key): - conditions[key] = value - - return conditions - -def get_chart_data(data): - if not data: - return None - - labels = ['Completed', 'Approved', 'Rejected'] - - status_wise_data = { - 'Completed': 0, - 'Approved': 0, - 'Rejected': 0 - } - - datasets = [] - - for entry in data: - status_wise_data[entry.status] += 1 - - datasets.append({ - 'name': 'Lab Test Status', - 'values': [status_wise_data.get('Completed'), status_wise_data.get('Approved'), status_wise_data.get('Rejected')] - }) - - chart = { - 'data': { - 'labels': labels, - 'datasets': datasets - }, - 'type': 'bar', - 'height': 300, - } - - return chart - - -def get_report_summary(data): - if not data: - return None - - total_lab_tests = len(data) - invoiced_lab_tests, unbilled_lab_tests = 0, 0 - - for entry in data: - if entry.invoiced: - invoiced_lab_tests += 1 - else: - unbilled_lab_tests += 1 - - return [ - { - 'value': total_lab_tests, - 'indicator': 'Blue', - 'label': 'Total Lab Tests', - 'datatype': 'Int', - }, - { - 'value': invoiced_lab_tests, - 'indicator': 'Green', - 'label': 'Invoiced Lab Tests', - 'datatype': 'Int', - }, - { - 'value': unbilled_lab_tests, - 'indicator': 'Red', - 'label': 'Unbilled Lab Tests', - 'datatype': 'Int', - } - ] diff --git a/erpnext/healthcare/report/patient_appointment_analytics/__init__.py b/erpnext/healthcare/report/patient_appointment_analytics/__init__.py deleted file mode 100644 index e69de29bb2d..00000000000 diff --git a/erpnext/healthcare/report/patient_appointment_analytics/patient_appointment_analytics.js b/erpnext/healthcare/report/patient_appointment_analytics/patient_appointment_analytics.js deleted file mode 100644 index 18d252ede13..00000000000 --- a/erpnext/healthcare/report/patient_appointment_analytics/patient_appointment_analytics.js +++ /dev/null @@ -1,128 +0,0 @@ -// Copyright (c) 2016, Frappe Technologies Pvt. Ltd. and contributors -// For license information, please see license.txt -/* eslint-disable */ - -frappe.query_reports['Patient Appointment Analytics'] = { - "filters": [ - { - fieldname: 'tree_type', - label: __('Tree Type'), - fieldtype: 'Select', - options: ['Healthcare Practitioner', 'Medical Department'], - default: 'Healthcare Practitioner', - reqd: 1 - }, - { - fieldname: 'status', - label: __('Appointment Status'), - fieldtype: 'Select', - options:[ - {label: __('Scheduled'), value: 'Scheduled'}, - {label: __('Open'), value: 'Open'}, - {label: __('Closed'), value: 'Closed'}, - {label: __('Expired'), value: 'Expired'}, - {label: __('Cancelled'), value: 'Cancelled'} - ] - }, - { - fieldname: 'appointment_type', - label: __('Appointment Type'), - fieldtype: 'Link', - options: 'Appointment Type' - }, - { - fieldname: 'practitioner', - label: __('Healthcare Practitioner'), - fieldtype: 'Link', - options: 'Healthcare Practitioner' - }, - { - fieldname: 'department', - label: __('Medical Department'), - fieldtype: 'Link', - options: 'Medical Department' - }, - { - fieldname: 'from_date', - label: __('From Date'), - fieldtype: 'Date', - default: frappe.defaults.get_user_default('year_start_date'), - reqd: 1 - }, - { - fieldname: 'to_date', - label: __('To Date'), - fieldtype: 'Date', - default: frappe.defaults.get_user_default('year_end_date'), - reqd: 1 - }, - { - fieldname: 'range', - label: __('Range'), - fieldtype: 'Select', - options:[ - {label: __('Weekly'), value: 'Weekly'}, - {label: __('Monthly'), value: 'Monthly'}, - {label: __('Quarterly'), value: 'Quarterly'}, - {label: __('Yearly'), value: 'Yearly'} - ], - default: 'Monthly', - reqd: 1 - } - ], - 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, - events: { - onCheckRow: function(data) { - row_name = data[2].content; - length = data.length; - - row_values = data.slice(3,length-1).map(function (column) { - return column.content; - }) - - entry = { - 'name': row_name, - 'values': row_values - } - - let raw_data = frappe.query_report.chart.data; - let new_datasets = raw_data.datasets; - - let found = false; - for (let i=0; i < new_datasets.length;i++) { - if (new_datasets[i].name == row_name) { - found = true; - new_datasets.splice(i,1); - break; - } - } - - if (!found) { - new_datasets.push(entry); - } - - let new_data = { - labels: raw_data.labels, - datasets: new_datasets - } - - setTimeout(() => { - frappe.query_report.chart.update(new_data) - }, 500) - - - setTimeout(() => { - frappe.query_report.chart.draw(true); - }, 1000) - - frappe.query_report.raw_chart_data = new_data; - }, - } - }) - }, -}; diff --git a/erpnext/healthcare/report/patient_appointment_analytics/patient_appointment_analytics.json b/erpnext/healthcare/report/patient_appointment_analytics/patient_appointment_analytics.json deleted file mode 100644 index 64750c012f1..00000000000 --- a/erpnext/healthcare/report/patient_appointment_analytics/patient_appointment_analytics.json +++ /dev/null @@ -1,36 +0,0 @@ -{ - "add_total_row": 1, - "creation": "2020-03-02 15:13:16.273493", - "disable_prepared_report": 0, - "disabled": 0, - "docstatus": 0, - "doctype": "Report", - "idx": 0, - "is_standard": "Yes", - "modified": "2020-03-02 15:13:16.273493", - "modified_by": "Administrator", - "module": "Healthcare", - "name": "Patient Appointment Analytics", - "owner": "Administrator", - "prepared_report": 0, - "ref_doctype": "Patient Appointment", - "report_name": "Patient Appointment Analytics", - "report_type": "Script Report", - "roles": [ - { - "role": "Healthcare Administrator" - }, - { - "role": "LabTest Approver" - }, - { - "role": "Physician" - }, - { - "role": "Nursing User" - }, - { - "role": "Laboratory User" - } - ] -} \ No newline at end of file diff --git a/erpnext/healthcare/report/patient_appointment_analytics/patient_appointment_analytics.py b/erpnext/healthcare/report/patient_appointment_analytics/patient_appointment_analytics.py deleted file mode 100644 index 1afb5da1fb4..00000000000 --- a/erpnext/healthcare/report/patient_appointment_analytics/patient_appointment_analytics.py +++ /dev/null @@ -1,197 +0,0 @@ -# Copyright (c) 2013, Frappe Technologies Pvt. Ltd. and contributors -# For license information, please see license.txt - -from __future__ import unicode_literals - -import frappe -from frappe import _, scrub -from frappe.utils import add_days, add_to_date, flt, getdate -from six import iteritems - -from erpnext.accounts.utils import get_fiscal_year - - -def execute(filters=None): - return Analytics(filters).run() - -class Analytics(object): - def __init__(self, filters=None): - """Patient Appointment Analytics Report.""" - self.filters = frappe._dict(filters or {}) - self.months = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'] - self.get_period_date_ranges() - - def run(self): - self.get_columns() - self.get_data() - self.get_chart_data() - - return self.columns, self.data, None, self.chart - - def get_period_date_ranges(self): - from dateutil.relativedelta import MO, relativedelta - from_date, to_date = getdate(self.filters.from_date), getdate(self.filters.to_date) - - increment = { - 'Monthly': 1, - 'Quarterly': 3, - 'Half-Yearly': 6, - 'Yearly': 12 - }.get(self.filters.range, 1) - - if self.filters.range in ['Monthly', 'Quarterly']: - from_date = from_date.replace(day=1) - elif self.filters.range == 'Yearly': - from_date = get_fiscal_year(from_date)[1] - else: - from_date = from_date + relativedelta(from_date, weekday=MO(-1)) - - self.periodic_daterange = [] - for dummy in range(1, 53): - if self.filters.range == 'Weekly': - period_end_date = add_days(from_date, 6) - else: - period_end_date = add_to_date(from_date, months=increment, days=-1) - - if period_end_date > to_date: - period_end_date = to_date - - self.periodic_daterange.append(period_end_date) - - from_date = add_days(period_end_date, 1) - if period_end_date == to_date: - break - - def get_columns(self): - self.columns = [] - - if self.filters.tree_type == 'Healthcare Practitioner': - self.columns.append({ - 'label': _('Healthcare Practitioner'), - 'options': 'Healthcare Practitioner', - 'fieldname': 'practitioner', - 'fieldtype': 'Link', - 'width': 200 - }) - - elif self.filters.tree_type == 'Medical Department': - self.columns.append({ - 'label': _('Medical Department'), - 'fieldname': 'department', - 'fieldtype': 'Link', - 'options': 'Medical Department', - 'width': 150 - }) - - for end_date in self.periodic_daterange: - period = self.get_period(end_date) - self.columns.append({ - 'label': _(period), - 'fieldname': scrub(period), - 'fieldtype': 'Int', - 'width': 120 - }) - - self.columns.append({ - 'label': _('Total'), - 'fieldname': 'total', - 'fieldtype': 'Int', - 'width': 120 - }) - - def get_data(self): - if self.filters.tree_type == 'Healthcare Practitioner': - self.get_appointments_based_on_healthcare_practitioner() - self.get_rows() - - elif self.filters.tree_type == 'Medical Department': - self.get_appointments_based_on_medical_department() - self.get_rows() - - def get_period(self, appointment_date): - if self.filters.range == 'Weekly': - period = 'Week ' + str(appointment_date.isocalendar()[1]) - elif self.filters.range == 'Monthly': - period = str(self.months[appointment_date.month - 1]) - elif self.filters.range == 'Quarterly': - period = 'Quarter ' + str(((appointment_date.month - 1) // 3) + 1) - else: - year = get_fiscal_year(appointment_date, company=self.filters.company) - period = str(year[0]) - - if getdate(self.filters.from_date).year != getdate(self.filters.to_date).year: - period += ' ' + str(appointment_date.year) - - return period - - def get_appointments_based_on_healthcare_practitioner(self): - filters = self.get_common_filters() - - self.entries = frappe.db.get_all('Patient Appointment', - fields=['appointment_date', 'name', 'patient', 'practitioner'], - filters=filters - ) - - def get_appointments_based_on_medical_department(self): - filters = self.get_common_filters() - if not filters.get('department'): - filters['department'] = ('!=', '') - - self.entries = frappe.db.get_all('Patient Appointment', - fields=['appointment_date', 'name', 'patient', 'practitioner', 'department'], - filters=filters - ) - - def get_common_filters(self): - filters = {} - filters['appointment_date'] = ('between', [self.filters.from_date, self.filters.to_date]) - for entry in ['appointment_type', 'practitioner', 'department', 'status']: - if self.filters.get(entry): - filters[entry] = self.filters.get(entry) - - return filters - - def get_rows(self): - self.data = [] - self.get_periodic_data() - - for entity, period_data in iteritems(self.appointment_periodic_data): - if self.filters.tree_type == 'Healthcare Practitioner': - row = {'practitioner': entity} - elif self.filters.tree_type == 'Medical Department': - row = {'department': entity} - - total = 0 - for end_date in self.periodic_daterange: - period = self.get_period(end_date) - amount = flt(period_data.get(period, 0.0)) - row[scrub(period)] = amount - total += amount - - row['total'] = total - - self.data.append(row) - - def get_periodic_data(self): - self.appointment_periodic_data = frappe._dict() - - for d in self.entries: - period = self.get_period(d.get('appointment_date')) - if self.filters.tree_type == 'Healthcare Practitioner': - self.appointment_periodic_data.setdefault(d.practitioner, frappe._dict()).setdefault(period, 0.0) - self.appointment_periodic_data[d.practitioner][period] += 1 - - elif self.filters.tree_type == 'Medical Department': - self.appointment_periodic_data.setdefault(d.department, frappe._dict()).setdefault(period, 0.0) - self.appointment_periodic_data[d.department][period] += 1 - - def get_chart_data(self): - length = len(self.columns) - labels = [d.get("label") for d in self.columns[1:length - 1]] - self.chart = { - "data": { - 'labels': labels, - 'datasets': [] - }, - "type": "line" - } diff --git a/erpnext/healthcare/setup.py b/erpnext/healthcare/setup.py deleted file mode 100644 index 891272ddf81..00000000000 --- a/erpnext/healthcare/setup.py +++ /dev/null @@ -1,295 +0,0 @@ -from __future__ import unicode_literals -import frappe - -from frappe import _ -from erpnext.setup.utils import insert_record - -def setup_healthcare(): - if frappe.db.exists('Medical Department', 'Cardiology'): - # already setup - return - create_medical_departments() - create_antibiotics() - create_lab_test_uom() - create_duration() - create_dosage() - create_healthcare_item_groups() - create_sensitivity() - add_healthcare_service_unit_tree_root() - setup_patient_history_settings() - -def create_medical_departments(): - departments = [ - "Accident And Emergency Care" ,"Anaesthetics", "Biochemistry", "Cardiology", "Dermatology", - "Diagnostic Imaging", "ENT", "Gastroenterology", "General Surgery", "Gynaecology", - "Haematology", "Maternity", "Microbiology", "Nephrology", "Neurology", "Oncology", - "Orthopaedics", "Pathology", "Physiotherapy", "Rheumatology", "Serology", "Urology" - ] - for department in departments: - mediacal_department = frappe.new_doc("Medical Department") - mediacal_department.department = _(department) - try: - mediacal_department.save() - except frappe.DuplicateEntryError: - pass - -def create_antibiotics(): - abt = [ - "Amoxicillin", "Ampicillin", "Bacampicillin", "Carbenicillin", "Cloxacillin", "Dicloxacillin", - "Flucloxacillin", "Mezlocillin", "Nafcillin", "Oxacillin", "Penicillin G", "Penicillin V", - "Piperacillin", "Pivampicillin", "Pivmecillinam", "Ticarcillin", "Cefacetrile (cephacetrile)", - "Cefadroxil (cefadroxyl)", "Cefalexin (cephalexin)", "Cefaloglycin (cephaloglycin)", - "Cefalonium (cephalonium)", "Cefaloridine (cephaloradine)", "Cefalotin (cephalothin)", - "Cefapirin (cephapirin)", "Cefatrizine", "Cefazaflur", "Cefazedone", "Cefazolin (cephazolin)", - "Cefradine (cephradine)", "Cefroxadine", "Ceftezole", "Cefaclor", "Cefamandole", "Cefmetazole", - "Cefonicid", "Cefotetan", "Cefoxitin", "Cefprozil (cefproxil)", "Cefuroxime", "Cefuzonam", - "Cefcapene", "Cefdaloxime", "Cefdinir", "Cefditoren", "Cefetamet", "Cefixime", "Cefmenoxime", - "Cefodizime", "Cefotaxime", "Cefpimizole", "Cefpodoxime", "Cefteram", "Ceftibuten", "Ceftiofur", - "Ceftiolene", "Ceftizoxime", "Ceftriaxone", "Cefoperazone", "Ceftazidime", "Cefclidine", "Cefepime", - "Cefluprenam", "Cefoselis", "Cefozopran", "Cefpirome", "Cefquinome", "Ceftobiprole", "Ceftaroline", - "Cefaclomezine","Cefaloram", "Cefaparole", "Cefcanel", "Cefedrolor", "Cefempidone", "Cefetrizole", - "Cefivitril", "Cefmatilen", "Cefmepidium", "Cefovecin", "Cefoxazole", "Cefrotil", "Cefsumide", - "Cefuracetime", "Ceftioxide", "Ceftazidime/Avibactam", "Ceftolozane/Tazobactam", "Aztreonam", - "Imipenem", "Imipenem/cilastatin", "Doripenem", "Meropenem", "Ertapenem", "Azithromycin", - "Erythromycin", "Clarithromycin", "Dirithromycin", "Roxithromycin", "Telithromycin", "Clindamycin", - "Lincomycin", "Pristinamycin", "Quinupristin/dalfopristin", "Amikacin", "Gentamicin", "Kanamycin", - "Neomycin", "Netilmicin", "Paromomycin", "Streptomycin", "Tobramycin", "Flumequine", "Nalidixic acid", - "Oxolinic acid", "Piromidic acid", "Pipemidic acid", "Rosoxacin", "Ciprofloxacin", "Enoxacin", - "Lomefloxacin", "Nadifloxacin", "Norfloxacin", "Ofloxacin", "Pefloxacin", "Rufloxacin", "Balofloxacin", - "Gatifloxacin", "Grepafloxacin", "Levofloxacin", "Moxifloxacin", "Pazufloxacin", "Sparfloxacin", - "Temafloxacin", "Tosufloxacin", "Besifloxacin", "Clinafloxacin", "Gemifloxacin", - "Sitafloxacin", "Trovafloxacin", "Prulifloxacin", "Sulfamethizole", "Sulfamethoxazole", - "Sulfisoxazole", "Trimethoprim-Sulfamethoxazole", "Demeclocycline", "Doxycycline", "Minocycline", - "Oxytetracycline", "Tetracycline", "Tigecycline", "Chloramphenicol", "Metronidazole", - "Tinidazole", "Nitrofurantoin", "Vancomycin", "Teicoplanin", "Telavancin", "Linezolid", - "Cycloserine 2", "Rifampin", "Rifabutin", "Rifapentine", "Rifalazil", "Bacitracin", "Polymyxin B", - "Viomycin", "Capreomycin" - ] - - for a in abt: - antibiotic = frappe.new_doc("Antibiotic") - antibiotic.antibiotic_name = a - try: - antibiotic.save() - except frappe.DuplicateEntryError: - pass - -def create_lab_test_uom(): - records = [ - {"doctype": "Lab Test UOM", "name": "umol/L", "lab_test_uom": "umol/L", "uom_description": None }, - {"doctype": "Lab Test UOM", "name": "mg/L", "lab_test_uom": "mg/L", "uom_description": None }, - {"doctype": "Lab Test UOM", "name": "mg / dl", "lab_test_uom": "mg / dl", "uom_description": None }, - {"doctype": "Lab Test UOM", "name": "pg / ml", "lab_test_uom": "pg / ml", "uom_description": None }, - {"doctype": "Lab Test UOM", "name": "U/ml", "lab_test_uom": "U/ml", "uom_description": None }, - {"doctype": "Lab Test UOM", "name": "/HPF", "lab_test_uom": "/HPF", "uom_description": None }, - {"doctype": "Lab Test UOM", "name": "Million Cells / cumm", "lab_test_uom": "Million Cells / cumm", "uom_description": None }, - {"doctype": "Lab Test UOM", "name": "Lakhs Cells / cumm", "lab_test_uom": "Lakhs Cells / cumm", "uom_description": None }, - {"doctype": "Lab Test UOM", "name": "U / L", "lab_test_uom": "U / L", "uom_description": None }, - {"doctype": "Lab Test UOM", "name": "g / L", "lab_test_uom": "g / L", "uom_description": None }, - {"doctype": "Lab Test UOM", "name": "IU / ml", "lab_test_uom": "IU / ml", "uom_description": None }, - {"doctype": "Lab Test UOM", "name": "gm %", "lab_test_uom": "gm %", "uom_description": None }, - {"doctype": "Lab Test UOM", "name": "Microgram", "lab_test_uom": "Microgram", "uom_description": None }, - {"doctype": "Lab Test UOM", "name": "Micron", "lab_test_uom": "Micron", "uom_description": None }, - {"doctype": "Lab Test UOM", "name": "Cells / cumm", "lab_test_uom": "Cells / cumm", "uom_description": None }, - {"doctype": "Lab Test UOM", "name": "%", "lab_test_uom": "%", "uom_description": None }, - {"doctype": "Lab Test UOM", "name": "mm / dl", "lab_test_uom": "mm / dl", "uom_description": None }, - {"doctype": "Lab Test UOM", "name": "mm / hr", "lab_test_uom": "mm / hr", "uom_description": None }, - {"doctype": "Lab Test UOM", "name": "ulU / ml", "lab_test_uom": "ulU / ml", "uom_description": None }, - {"doctype": "Lab Test UOM", "name": "ng / ml", "lab_test_uom": "ng / ml", "uom_description": None }, - {"doctype": "Lab Test UOM", "name": "ng / dl", "lab_test_uom": "ng / dl", "uom_description": None }, - {"doctype": "Lab Test UOM", "name": "ug / dl", "lab_test_uom": "ug / dl", "uom_description": None } - ] - - insert_record(records) - -def create_duration(): - records = [ - {"doctype": "Prescription Duration", "name": "3 Month", "number": "3", "period": "Month" }, - {"doctype": "Prescription Duration", "name": "2 Month", "number": "2", "period": "Month" }, - {"doctype": "Prescription Duration", "name": "1 Month", "number": "1", "period": "Month" }, - {"doctype": "Prescription Duration", "name": "12 Hour", "number": "12", "period": "Hour" }, - {"doctype": "Prescription Duration", "name": "11 Hour", "number": "11", "period": "Hour" }, - {"doctype": "Prescription Duration", "name": "10 Hour", "number": "10", "period": "Hour" }, - {"doctype": "Prescription Duration", "name": "9 Hour", "number": "9", "period": "Hour" }, - {"doctype": "Prescription Duration", "name": "8 Hour", "number": "8", "period": "Hour" }, - {"doctype": "Prescription Duration", "name": "7 Hour", "number": "7", "period": "Hour" }, - {"doctype": "Prescription Duration", "name": "6 Hour", "number": "6", "period": "Hour" }, - {"doctype": "Prescription Duration", "name": "5 Hour", "number": "5", "period": "Hour" }, - {"doctype": "Prescription Duration", "name": "4 Hour", "number": "4", "period": "Hour" }, - {"doctype": "Prescription Duration", "name": "3 Hour", "number": "3", "period": "Hour" }, - {"doctype": "Prescription Duration", "name": "2 Hour", "number": "2", "period": "Hour" }, - {"doctype": "Prescription Duration", "name": "1 Hour", "number": "1", "period": "Hour" }, - {"doctype": "Prescription Duration", "name": "5 Week", "number": "5", "period": "Week" }, - {"doctype": "Prescription Duration", "name": "4 Week", "number": "4", "period": "Week" }, - {"doctype": "Prescription Duration", "name": "3 Week", "number": "3", "period": "Week" }, - {"doctype": "Prescription Duration", "name": "2 Week", "number": "2", "period": "Week" }, - {"doctype": "Prescription Duration", "name": "1 Week", "number": "1", "period": "Week" }, - {"doctype": "Prescription Duration", "name": "6 Day", "number": "6", "period": "Day" }, - {"doctype": "Prescription Duration", "name": "5 Day", "number": "5", "period": "Day" }, - {"doctype": "Prescription Duration", "name": "4 Day", "number": "4", "period": "Day" }, - {"doctype": "Prescription Duration", "name": "3 Day", "number": "3", "period": "Day" }, - {"doctype": "Prescription Duration", "name": "2 Day", "number": "2", "period": "Day" }, - {"doctype": "Prescription Duration", "name": "1 Day", "number": "1", "period": "Day" } - ] - insert_record(records) - -def create_dosage(): - records = [ - {"doctype": "Prescription Dosage", "name": "1-1-1-1", "dosage": "1-1-1-1","dosage_strength": - [{"strength": "1.0","strength_time": "9:00:00"}, {"strength": "1.0","strength_time": "13:00:00"},{"strength": "1.0","strength_time": "17:00:00"},{"strength": "1.0","strength_time": "21:00:00"}] - }, - {"doctype": "Prescription Dosage", "name": "0-0-1", "dosage": "0-0-1","dosage_strength": - [{"strength": "1.0","strength_time": "21:00:00"}] - }, - {"doctype": "Prescription Dosage", "name": "1-0-0", "dosage": "1-0-0","dosage_strength": - [{"strength": "1.0","strength_time": "9:00:00"}] - }, - {"doctype": "Prescription Dosage", "name": "0-1-0", "dosage": "0-1-0","dosage_strength": - [{"strength": "1.0","strength_time": "14:00:00"}] - }, - {"doctype": "Prescription Dosage", "name": "1-1-1", "dosage": "1-1-1","dosage_strength": - [{"strength": "1.0","strength_time": "9:00:00"}, {"strength": "1.0","strength_time": "14:00:00"},{"strength": "1.0","strength_time": "21:00:00"}] - }, - {"doctype": "Prescription Dosage", "name": "1-0-1", "dosage": "1-0-1","dosage_strength": - [{"strength": "1.0","strength_time": "9:00:00"}, {"strength": "1.0","strength_time": "21:00:00"}] - }, - {"doctype": "Prescription Dosage", "name": "Once Bedtime", "dosage": "Once Bedtime","dosage_strength": - [{"strength": "1.0","strength_time": "21:00:00"}] - }, - {"doctype": "Prescription Dosage", "name": "5 times a day", "dosage": "5 times a day","dosage_strength": - [{"strength": "1.0","strength_time": "5:00:00"}, {"strength": "1.0","strength_time": "9:00:00"}, {"strength": "1.0","strength_time": "13:00:00"},{"strength": "1.0","strength_time": "17:00:00"},{"strength": "1.0","strength_time": "21:00:00"}] - }, - {"doctype": "Prescription Dosage", "name": "QID", "dosage": "QID","dosage_strength": - [{"strength": "1.0","strength_time": "9:00:00"}, {"strength": "1.0","strength_time": "13:00:00"},{"strength": "1.0","strength_time": "17:00:00"},{"strength": "1.0","strength_time": "21:00:00"}] - }, - {"doctype": "Prescription Dosage", "name": "TID", "dosage": "TID","dosage_strength": - [{"strength": "1.0","strength_time": "9:00:00"}, {"strength": "1.0","strength_time": "14:00:00"},{"strength": "1.0","strength_time": "21:00:00"}] - }, - {"doctype": "Prescription Dosage", "name": "BID", "dosage": "BID","dosage_strength": - [{"strength": "1.0","strength_time": "9:00:00"}, {"strength": "1.0","strength_time": "21:00:00"}] - }, - {"doctype": "Prescription Dosage", "name": "Once Daily", "dosage": "Once Daily","dosage_strength": - [{"strength": "1.0","strength_time": "9:00:00"}] - } - ] - insert_record(records) - -def create_healthcare_item_groups(): - records = [ - {'doctype': 'Item Group', 'item_group_name': _('Laboratory'), - 'is_group': 0, 'parent_item_group': _('All Item Groups') }, - {'doctype': 'Item Group', 'item_group_name': _('Drug'), - 'is_group': 0, 'parent_item_group': _('All Item Groups') } - ] - insert_record(records) - -def create_sensitivity(): - records = [ - {"doctype": "Sensitivity", "sensitivity": _("Low Sensitivity")}, - {"doctype": "Sensitivity", "sensitivity": _("High Sensitivity")}, - {"doctype": "Sensitivity", "sensitivity": _("Moderate Sensitivity")}, - {"doctype": "Sensitivity", "sensitivity": _("Susceptible")}, - {"doctype": "Sensitivity", "sensitivity": _("Resistant")}, - {"doctype": "Sensitivity", "sensitivity": _("Intermediate")} - ] - insert_record(records) - -def add_healthcare_service_unit_tree_root(): - record = [ - { - "doctype": "Healthcare Service Unit", - "healthcare_service_unit_name": "All Healthcare Service Units", - "is_group": 1, - "company": get_company() - } - ] - insert_record(record) - -def get_company(): - company = frappe.defaults.get_defaults().company - if company: - return company - else: - company = frappe.get_list("Company", limit=1) - if company: - return company[0].name - return None - -def setup_patient_history_settings(): - import json - - settings = frappe.get_single('Patient History Settings') - configuration = get_patient_history_config() - for dt, config in configuration.items(): - settings.append("standard_doctypes", { - "document_type": dt, - "date_fieldname": config[0], - "selected_fields": json.dumps(config[1]) - }) - settings.save() - -def get_patient_history_config(): - return { - "Patient Encounter": ("encounter_date", [ - {"label": "Healthcare Practitioner", "fieldname": "practitioner", "fieldtype": "Link"}, - {"label": "Symptoms", "fieldname": "symptoms", "fieldtype": "Table Multiselect"}, - {"label": "Diagnosis", "fieldname": "diagnosis", "fieldtype": "Table Multiselect"}, - {"label": "Drug Prescription", "fieldname": "drug_prescription", "fieldtype": "Table"}, - {"label": "Lab Tests", "fieldname": "lab_test_prescription", "fieldtype": "Table"}, - {"label": "Clinical Procedures", "fieldname": "procedure_prescription", "fieldtype": "Table"}, - {"label": "Therapies", "fieldname": "therapies", "fieldtype": "Table"}, - {"label": "Review Details", "fieldname": "encounter_comment", "fieldtype": "Small Text"} - ]), - "Clinical Procedure": ("start_date", [ - {"label": "Procedure Template", "fieldname": "procedure_template", "fieldtype": "Link"}, - {"label": "Healthcare Practitioner", "fieldname": "practitioner", "fieldtype": "Link"}, - {"label": "Notes", "fieldname": "notes", "fieldtype": "Small Text"}, - {"label": "Service Unit", "fieldname": "service_unit", "fieldtype": "Healthcare Service Unit"}, - {"label": "Start Time", "fieldname": "start_time", "fieldtype": "Time"}, - {"label": "Sample", "fieldname": "sample", "fieldtype": "Link"} - ]), - "Lab Test": ("result_date", [ - {"label": "Test Template", "fieldname": "template", "fieldtype": "Link"}, - {"label": "Healthcare Practitioner", "fieldname": "practitioner", "fieldtype": "Link"}, - {"label": "Test Name", "fieldname": "lab_test_name", "fieldtype": "Data"}, - {"label": "Lab Technician Name", "fieldname": "employee_name", "fieldtype": "Data"}, - {"label": "Sample ID", "fieldname": "sample", "fieldtype": "Link"}, - {"label": "Normal Test Result", "fieldname": "normal_test_items", "fieldtype": "Table"}, - {"label": "Descriptive Test Result", "fieldname": "descriptive_test_items", "fieldtype": "Table"}, - {"label": "Organism Test Result", "fieldname": "organism_test_items", "fieldtype": "Table"}, - {"label": "Sensitivity Test Result", "fieldname": "sensitivity_test_items", "fieldtype": "Table"}, - {"label": "Comments", "fieldname": "lab_test_comment", "fieldtype": "Table"} - ]), - "Therapy Session": ("start_date", [ - {"label": "Therapy Type", "fieldname": "therapy_type", "fieldtype": "Link"}, - {"label": "Healthcare Practitioner", "fieldname": "practitioner", "fieldtype": "Link"}, - {"label": "Therapy Plan", "fieldname": "therapy_plan", "fieldtype": "Link"}, - {"label": "Duration", "fieldname": "duration", "fieldtype": "Int"}, - {"label": "Location", "fieldname": "location", "fieldtype": "Link"}, - {"label": "Healthcare Service Unit", "fieldname": "service_unit", "fieldtype": "Link"}, - {"label": "Start Time", "fieldname": "start_time", "fieldtype": "Time"}, - {"label": "Exercises", "fieldname": "exercises", "fieldtype": "Table"}, - {"label": "Total Counts Targeted", "fieldname": "total_counts_targeted", "fieldtype": "Int"}, - {"label": "Total Counts Completed", "fieldname": "total_counts_completed", "fieldtype": "Int"} - ]), - "Vital Signs": ("signs_date", [ - {"label": "Body Temperature", "fieldname": "temperature", "fieldtype": "Data"}, - {"label": "Heart Rate / Pulse", "fieldname": "pulse", "fieldtype": "Data"}, - {"label": "Respiratory rate", "fieldname": "respiratory_rate", "fieldtype": "Data"}, - {"label": "Tongue", "fieldname": "tongue", "fieldtype": "Select"}, - {"label": "Abdomen", "fieldname": "abdomen", "fieldtype": "Select"}, - {"label": "Reflexes", "fieldname": "reflexes", "fieldtype": "Select"}, - {"label": "Blood Pressure", "fieldname": "bp", "fieldtype": "Data"}, - {"label": "Notes", "fieldname": "vital_signs_note", "fieldtype": "Small Text"}, - {"label": "Height (In Meter)", "fieldname": "height", "fieldtype": "Float"}, - {"label": "Weight (In Kilogram)", "fieldname": "weight", "fieldtype": "Float"}, - {"label": "BMI", "fieldname": "bmi", "fieldtype": "Float"} - ]), - "Inpatient Medication Order": ("start_date", [ - {"label": "Healthcare Practitioner", "fieldname": "practitioner", "fieldtype": "Link"}, - {"label": "Start Date", "fieldname": "start_date", "fieldtype": "Date"}, - {"label": "End Date", "fieldname": "end_date", "fieldtype": "Date"}, - {"label": "Medication Orders", "fieldname": "medication_orders", "fieldtype": "Table"}, - {"label": "Total Orders", "fieldname": "total_orders", "fieldtype": "Float"} - ]) - } diff --git a/erpnext/healthcare/utils.py b/erpnext/healthcare/utils.py deleted file mode 100644 index cae3008ca82..00000000000 --- a/erpnext/healthcare/utils.py +++ /dev/null @@ -1,792 +0,0 @@ -# -*- coding: utf-8 -*- -# Copyright (c) 2018, earthians and contributors -# For license information, please see license.txt - -from __future__ import unicode_literals - -import json -import math - -import frappe -from frappe import _ -from frappe.utils import cstr, rounded, time_diff_in_hours -from frappe.utils.formatters import format_value - -from erpnext.healthcare.doctype.fee_validity.fee_validity import create_fee_validity -from erpnext.healthcare.doctype.healthcare_settings.healthcare_settings import get_income_account -from erpnext.healthcare.doctype.lab_test.lab_test import create_multiple - - -@frappe.whitelist() -def get_healthcare_services_to_invoice(patient, company): - patient = frappe.get_doc('Patient', patient) - items_to_invoice = [] - if patient: - validate_customer_created(patient) - # Customer validated, build a list of billable services - items_to_invoice += get_appointments_to_invoice(patient, company) - items_to_invoice += get_encounters_to_invoice(patient, company) - items_to_invoice += get_lab_tests_to_invoice(patient, company) - items_to_invoice += get_clinical_procedures_to_invoice(patient, company) - items_to_invoice += get_inpatient_services_to_invoice(patient, company) - items_to_invoice += get_therapy_plans_to_invoice(patient, company) - items_to_invoice += get_therapy_sessions_to_invoice(patient, company) - - return items_to_invoice - - -def validate_customer_created(patient): - if not frappe.db.get_value('Patient', patient.name, 'customer'): - msg = _("Please set a Customer linked to the Patient") - msg += " {0}".format(patient.name) - frappe.throw(msg, title=_('Customer Not Found')) - - -def get_appointments_to_invoice(patient, company): - appointments_to_invoice = [] - patient_appointments = frappe.get_list( - 'Patient Appointment', - fields = '*', - filters = {'patient': patient.name, 'company': company, 'invoiced': 0, 'status': ['not in', 'Cancelled']}, - order_by = 'appointment_date' - ) - - for appointment in patient_appointments: - # Procedure Appointments - if appointment.procedure_template: - if frappe.db.get_value('Clinical Procedure Template', appointment.procedure_template, 'is_billable'): - appointments_to_invoice.append({ - 'reference_type': 'Patient Appointment', - 'reference_name': appointment.name, - 'service': appointment.procedure_template - }) - # Consultation Appointments, should check fee validity - else: - if frappe.db.get_single_value('Healthcare Settings', 'enable_free_follow_ups') and \ - frappe.db.exists('Fee Validity Reference', {'appointment': appointment.name}): - continue # Skip invoicing, fee validty present - practitioner_charge = 0 - income_account = None - service_item = None - if appointment.practitioner: - details = get_service_item_and_practitioner_charge(appointment) - service_item = details.get('service_item') - practitioner_charge = details.get('practitioner_charge') - income_account = get_income_account(appointment.practitioner, appointment.company) - appointments_to_invoice.append({ - 'reference_type': 'Patient Appointment', - 'reference_name': appointment.name, - 'service': service_item, - 'rate': practitioner_charge, - 'income_account': income_account - }) - - return appointments_to_invoice - - -def get_encounters_to_invoice(patient, company): - if not isinstance(patient, str): - patient = patient.name - encounters_to_invoice = [] - encounters = frappe.get_list( - 'Patient Encounter', - fields=['*'], - filters={'patient': patient, 'company': company, 'invoiced': False, 'docstatus': 1} - ) - if encounters: - for encounter in encounters: - if not encounter.appointment: - practitioner_charge = 0 - income_account = None - service_item = None - if encounter.practitioner: - if encounter.inpatient_record and \ - frappe.db.get_single_value('Healthcare Settings', 'do_not_bill_inpatient_encounters'): - continue - - details = get_service_item_and_practitioner_charge(encounter) - service_item = details.get('service_item') - practitioner_charge = details.get('practitioner_charge') - income_account = get_income_account(encounter.practitioner, encounter.company) - - encounters_to_invoice.append({ - 'reference_type': 'Patient Encounter', - 'reference_name': encounter.name, - 'service': service_item, - 'rate': practitioner_charge, - 'income_account': income_account - }) - - return encounters_to_invoice - - -def get_lab_tests_to_invoice(patient, company): - lab_tests_to_invoice = [] - lab_tests = frappe.get_list( - 'Lab Test', - fields=['name', 'template'], - filters={'patient': patient.name, 'company': company, 'invoiced': False, 'docstatus': 1} - ) - for lab_test in lab_tests: - item, is_billable = frappe.get_cached_value('Lab Test Template', lab_test.template, ['item', 'is_billable']) - if is_billable: - lab_tests_to_invoice.append({ - 'reference_type': 'Lab Test', - 'reference_name': lab_test.name, - 'service': item - }) - - lab_prescriptions = frappe.db.sql( - ''' - SELECT - lp.name, lp.lab_test_code - FROM - `tabPatient Encounter` et, `tabLab Prescription` lp - WHERE - et.patient=%s - and lp.parent=et.name - and lp.lab_test_created=0 - and lp.invoiced=0 - ''', (patient.name), as_dict=1) - - for prescription in lab_prescriptions: - item, is_billable = frappe.get_cached_value('Lab Test Template', prescription.lab_test_code, ['item', 'is_billable']) - if prescription.lab_test_code and is_billable: - lab_tests_to_invoice.append({ - 'reference_type': 'Lab Prescription', - 'reference_name': prescription.name, - 'service': item - }) - - return lab_tests_to_invoice - - -def get_clinical_procedures_to_invoice(patient, company): - clinical_procedures_to_invoice = [] - procedures = frappe.get_list( - 'Clinical Procedure', - fields='*', - filters={'patient': patient.name, 'company': company, 'invoiced': False} - ) - for procedure in procedures: - if not procedure.appointment: - item, is_billable = frappe.get_cached_value('Clinical Procedure Template', procedure.procedure_template, ['item', 'is_billable']) - if procedure.procedure_template and is_billable: - clinical_procedures_to_invoice.append({ - 'reference_type': 'Clinical Procedure', - 'reference_name': procedure.name, - 'service': item - }) - - # consumables - if procedure.invoice_separately_as_consumables and procedure.consume_stock \ - and procedure.status == 'Completed' and not procedure.consumption_invoiced: - - service_item = frappe.db.get_single_value('Healthcare Settings', 'clinical_procedure_consumable_item') - if not service_item: - frappe.throw(_('Please configure Clinical Procedure Consumable Item in {0}').format( - frappe.utils.get_link_to_form('Healthcare Settings', 'Healthcare Settings')), - title=_('Missing Configuration')) - - clinical_procedures_to_invoice.append({ - 'reference_type': 'Clinical Procedure', - 'reference_name': procedure.name, - 'service': service_item, - 'rate': procedure.consumable_total_amount, - 'description': procedure.consumption_details - }) - - procedure_prescriptions = frappe.db.sql( - ''' - SELECT - pp.name, pp.procedure - FROM - `tabPatient Encounter` et, `tabProcedure Prescription` pp - WHERE - et.patient=%s - and pp.parent=et.name - and pp.procedure_created=0 - and pp.invoiced=0 - and pp.appointment_booked=0 - ''', (patient.name), as_dict=1) - - for prescription in procedure_prescriptions: - item, is_billable = frappe.get_cached_value('Clinical Procedure Template', prescription.procedure, ['item', 'is_billable']) - if is_billable: - clinical_procedures_to_invoice.append({ - 'reference_type': 'Procedure Prescription', - 'reference_name': prescription.name, - 'service': item - }) - - return clinical_procedures_to_invoice - - -def get_inpatient_services_to_invoice(patient, company): - services_to_invoice = [] - inpatient_services = frappe.db.sql( - ''' - SELECT - io.* - FROM - `tabInpatient Record` ip, `tabInpatient Occupancy` io - WHERE - ip.patient=%s - and ip.company=%s - and io.parent=ip.name - and io.left=1 - and io.invoiced=0 - ''', (patient.name, company), as_dict=1) - - for inpatient_occupancy in inpatient_services: - service_unit_type = frappe.db.get_value('Healthcare Service Unit', inpatient_occupancy.service_unit, 'service_unit_type') - service_unit_type = frappe.get_cached_doc('Healthcare Service Unit Type', service_unit_type) - if service_unit_type and service_unit_type.is_billable: - hours_occupied = time_diff_in_hours(inpatient_occupancy.check_out, inpatient_occupancy.check_in) - qty = 0.5 - if hours_occupied > 0: - actual_qty = hours_occupied / service_unit_type.no_of_hours - floor = math.floor(actual_qty) - decimal_part = actual_qty - floor - if decimal_part > 0.5: - qty = rounded(floor + 1, 1) - elif decimal_part < 0.5 and decimal_part > 0: - qty = rounded(floor + 0.5, 1) - if qty <= 0: - qty = 0.5 - services_to_invoice.append({ - 'reference_type': 'Inpatient Occupancy', - 'reference_name': inpatient_occupancy.name, - 'service': service_unit_type.item, 'qty': qty - }) - - return services_to_invoice - - -def get_therapy_plans_to_invoice(patient, company): - therapy_plans_to_invoice = [] - therapy_plans = frappe.get_list( - 'Therapy Plan', - fields=['therapy_plan_template', 'name'], - filters={ - 'patient': patient.name, - 'invoiced': 0, - 'company': company, - 'therapy_plan_template': ('!=', '') - } - ) - for plan in therapy_plans: - therapy_plans_to_invoice.append({ - 'reference_type': 'Therapy Plan', - 'reference_name': plan.name, - 'service': frappe.db.get_value('Therapy Plan Template', plan.therapy_plan_template, 'linked_item') - }) - - return therapy_plans_to_invoice - - -def get_therapy_sessions_to_invoice(patient, company): - therapy_sessions_to_invoice = [] - therapy_plans = frappe.db.get_all('Therapy Plan', {'therapy_plan_template': ('!=', '')}) - therapy_plans_created_from_template = [] - for entry in therapy_plans: - therapy_plans_created_from_template.append(entry.name) - - therapy_sessions = frappe.get_list( - 'Therapy Session', - fields='*', - filters={ - 'patient': patient.name, - 'invoiced': 0, - 'company': company, - 'therapy_plan': ('not in', therapy_plans_created_from_template) - } - ) - for therapy in therapy_sessions: - if not therapy.appointment: - if therapy.therapy_type and frappe.db.get_value('Therapy Type', therapy.therapy_type, 'is_billable'): - therapy_sessions_to_invoice.append({ - 'reference_type': 'Therapy Session', - 'reference_name': therapy.name, - 'service': frappe.db.get_value('Therapy Type', therapy.therapy_type, 'item') - }) - - return therapy_sessions_to_invoice - -@frappe.whitelist() -def get_service_item_and_practitioner_charge(doc): - if isinstance(doc, str): - doc = json.loads(doc) - doc = frappe.get_doc(doc) - - service_item = None - practitioner_charge = None - department = doc.medical_department if doc.doctype == 'Patient Encounter' else doc.department - - is_inpatient = doc.inpatient_record - - if doc.get('appointment_type'): - service_item, practitioner_charge = get_appointment_type_service_item(doc.appointment_type, department, is_inpatient) - - if not service_item and not practitioner_charge: - service_item, practitioner_charge = get_practitioner_service_item(doc.practitioner, is_inpatient) - if not service_item: - service_item = get_healthcare_service_item(is_inpatient) - - if not service_item: - throw_config_service_item(is_inpatient) - - if not practitioner_charge: - throw_config_practitioner_charge(is_inpatient, doc.practitioner) - - return {'service_item': service_item, 'practitioner_charge': practitioner_charge} - - -def get_appointment_type_service_item(appointment_type, department, is_inpatient): - from erpnext.healthcare.doctype.appointment_type.appointment_type import ( - get_service_item_based_on_department, - ) - - item_list = get_service_item_based_on_department(appointment_type, department) - service_item = None - practitioner_charge = None - - if item_list: - if is_inpatient: - service_item = item_list.get('inpatient_visit_charge_item') - practitioner_charge = item_list.get('inpatient_visit_charge') - else: - service_item = item_list.get('op_consulting_charge_item') - practitioner_charge = item_list.get('op_consulting_charge') - - return service_item, practitioner_charge - - -def throw_config_service_item(is_inpatient): - service_item_label = _('Out Patient Consulting Charge Item') - if is_inpatient: - service_item_label = _('Inpatient Visit Charge Item') - - msg = _(('Please Configure {0} in ').format(service_item_label) \ - + '''Healthcare Settings''') - frappe.throw(msg, title=_('Missing Configuration')) - - -def throw_config_practitioner_charge(is_inpatient, practitioner): - charge_name = _('OP Consulting Charge') - if is_inpatient: - charge_name = _('Inpatient Visit Charge') - - msg = _(('Please Configure {0} for Healthcare Practitioner').format(charge_name) \ - + ''' {0}'''.format(practitioner)) - frappe.throw(msg, title=_('Missing Configuration')) - - -def get_practitioner_service_item(practitioner, is_inpatient): - service_item = None - practitioner_charge = None - - if is_inpatient: - service_item, practitioner_charge = frappe.db.get_value('Healthcare Practitioner', practitioner, ['inpatient_visit_charge_item', 'inpatient_visit_charge']) - else: - service_item, practitioner_charge = frappe.db.get_value('Healthcare Practitioner', practitioner, ['op_consulting_charge_item', 'op_consulting_charge']) - - return service_item, practitioner_charge - - -def get_healthcare_service_item(is_inpatient): - service_item = None - - if is_inpatient: - service_item = frappe.db.get_single_value('Healthcare Settings', 'inpatient_visit_charge_item') - else: - service_item = frappe.db.get_single_value('Healthcare Settings', 'op_consulting_charge_item') - - return service_item - - -def get_practitioner_charge(practitioner, is_inpatient): - if is_inpatient: - practitioner_charge = frappe.db.get_value('Healthcare Practitioner', practitioner, 'inpatient_visit_charge') - else: - practitioner_charge = frappe.db.get_value('Healthcare Practitioner', practitioner, 'op_consulting_charge') - if practitioner_charge: - return practitioner_charge - return False - - -def manage_invoice_submit_cancel(doc, method): - if doc.items: - for item in doc.items: - if item.get('reference_dt') and item.get('reference_dn'): - if frappe.get_meta(item.reference_dt).has_field('invoiced'): - set_invoiced(item, method, doc.name) - - if method=='on_submit' and frappe.db.get_single_value('Healthcare Settings', 'create_lab_test_on_si_submit'): - create_multiple('Sales Invoice', doc.name) - - -def set_invoiced(item, method, ref_invoice=None): - invoiced = False - if method=='on_submit': - validate_invoiced_on_submit(item) - invoiced = True - - if item.reference_dt == 'Clinical Procedure': - service_item = frappe.db.get_single_value('Healthcare Settings', 'clinical_procedure_consumable_item') - if service_item == item.item_code: - frappe.db.set_value(item.reference_dt, item.reference_dn, 'consumption_invoiced', invoiced) - else: - frappe.db.set_value(item.reference_dt, item.reference_dn, 'invoiced', invoiced) - else: - frappe.db.set_value(item.reference_dt, item.reference_dn, 'invoiced', invoiced) - - if item.reference_dt == 'Patient Appointment': - if frappe.db.get_value('Patient Appointment', item.reference_dn, 'procedure_template'): - dt_from_appointment = 'Clinical Procedure' - else: - dt_from_appointment = 'Patient Encounter' - manage_doc_for_appointment(dt_from_appointment, item.reference_dn, invoiced) - - elif item.reference_dt == 'Lab Prescription': - manage_prescriptions(invoiced, item.reference_dt, item.reference_dn, 'Lab Test', 'lab_test_created') - - elif item.reference_dt == 'Procedure Prescription': - manage_prescriptions(invoiced, item.reference_dt, item.reference_dn, 'Clinical Procedure', 'procedure_created') - - -def validate_invoiced_on_submit(item): - if item.reference_dt == 'Clinical Procedure' and \ - frappe.db.get_single_value('Healthcare Settings', 'clinical_procedure_consumable_item') == item.item_code: - is_invoiced = frappe.db.get_value(item.reference_dt, item.reference_dn, 'consumption_invoiced') - else: - is_invoiced = frappe.db.get_value(item.reference_dt, item.reference_dn, 'invoiced') - if is_invoiced: - frappe.throw(_('The item referenced by {0} - {1} is already invoiced').format( - item.reference_dt, item.reference_dn)) - - -def manage_prescriptions(invoiced, ref_dt, ref_dn, dt, created_check_field): - created = frappe.db.get_value(ref_dt, ref_dn, created_check_field) - if created: - # Fetch the doc created for the prescription - doc_created = frappe.db.get_value(dt, {'prescription': ref_dn}) - frappe.db.set_value(dt, doc_created, 'invoiced', invoiced) - - -def check_fee_validity(appointment): - if not frappe.db.get_single_value('Healthcare Settings', 'enable_free_follow_ups'): - return - - validity = frappe.db.exists('Fee Validity', { - 'practitioner': appointment.practitioner, - 'patient': appointment.patient, - 'valid_till': ('>=', appointment.appointment_date) - }) - if not validity: - return - - validity = frappe.get_doc('Fee Validity', validity) - return validity - - -def manage_fee_validity(appointment): - fee_validity = check_fee_validity(appointment) - - if fee_validity: - if appointment.status == 'Cancelled' and fee_validity.visited > 0: - fee_validity.visited -= 1 - frappe.db.delete('Fee Validity Reference', {'appointment': appointment.name}) - elif fee_validity.status == 'Completed': - return - else: - fee_validity.visited += 1 - fee_validity.append('ref_appointments', { - 'appointment': appointment.name - }) - fee_validity.save(ignore_permissions=True) - else: - fee_validity = create_fee_validity(appointment) - return fee_validity - - -def manage_doc_for_appointment(dt_from_appointment, appointment, invoiced): - dn_from_appointment = frappe.db.get_value( - dt_from_appointment, - filters={'appointment': appointment} - ) - if dn_from_appointment: - frappe.db.set_value(dt_from_appointment, dn_from_appointment, 'invoiced', invoiced) - - -@frappe.whitelist() -def get_drugs_to_invoice(encounter): - encounter = frappe.get_doc('Patient Encounter', encounter) - if encounter: - patient = frappe.get_doc('Patient', encounter.patient) - if patient: - if patient.customer: - items_to_invoice = [] - for drug_line in encounter.drug_prescription: - if drug_line.drug_code: - qty = 1 - if frappe.db.get_value('Item', drug_line.drug_code, 'stock_uom') == 'Nos': - qty = drug_line.get_quantity() - - description = '' - if drug_line.dosage and drug_line.period: - description = _('{0} for {1}').format(drug_line.dosage, drug_line.period) - - items_to_invoice.append({ - 'drug_code': drug_line.drug_code, - 'quantity': qty, - 'description': description - }) - return items_to_invoice - else: - validate_customer_created(patient) - - -@frappe.whitelist() -def get_children(doctype, parent=None, company=None, is_root=False): - parent_fieldname = 'parent_' + doctype.lower().replace(' ', '_') - fields = [ - 'name as value', - 'is_group as expandable', - 'lft', - 'rgt' - ] - - filters = [["ifnull(`{0}`,'')".format(parent_fieldname), - '=', '' if is_root else parent]] - - if is_root: - fields += ['service_unit_type'] if doctype == 'Healthcare Service Unit' else [] - filters.append(['company', '=', company]) - else: - fields += ['service_unit_type', 'allow_appointments', 'inpatient_occupancy', - 'occupancy_status'] if doctype == 'Healthcare Service Unit' else [] - fields += [parent_fieldname + ' as parent'] - - service_units = frappe.get_list(doctype, fields=fields, filters=filters) - for each in service_units: - if each['expandable'] == 1: # group node - available_count = frappe.db.count('Healthcare Service Unit', filters={ - 'parent_healthcare_service_unit': each['value'], - 'inpatient_occupancy': 1}) - - if available_count > 0: - occupied_count = frappe.db.count('Healthcare Service Unit', { - 'parent_healthcare_service_unit': each['value'], - 'inpatient_occupancy': 1, - 'occupancy_status': 'Occupied'}) - # set occupancy status of group node - each['occupied_of_available'] = str( - occupied_count) + ' Occupied of ' + str(available_count) - - return service_units - - -@frappe.whitelist() -def get_patient_vitals(patient, from_date=None, to_date=None): - if not patient: return - - vitals = frappe.db.get_all('Vital Signs', filters={ - 'docstatus': 1, - 'patient': patient - }, order_by='signs_date, signs_time', fields=['*']) - - if len(vitals): - return vitals - return False - - -@frappe.whitelist() -def render_docs_as_html(docs): - # docs key value pair {doctype: docname} - docs_html = "
" - for doc in docs: - docs_html += render_doc_as_html(doc['doctype'], doc['docname'])['html'] + '
' - return {'html': docs_html} - - -@frappe.whitelist() -def render_doc_as_html(doctype, docname, exclude_fields = []): - """ - Render document as HTML - """ - - doc = frappe.get_doc(doctype, docname) - meta = frappe.get_meta(doctype) - doc_html = section_html = section_label = html = "" - sec_on = has_data = False - col_on = 0 - - for df in meta.fields: - # on section break append previous section and html to doc html - if df.fieldtype == "Section Break": - if has_data and col_on and sec_on: - doc_html += section_html + html + "
" - - elif has_data and not col_on and sec_on: - doc_html += """ -
-
-
- {0} -
-
-
-
- {1} {2} -
-
- """.format(section_label, section_html, html) - - # close divs for columns - while col_on: - doc_html += "" - col_on -= 1 - - sec_on = True - has_data = False - col_on = 0 - section_html = html = "" - - if df.label: - section_label = df.label - continue - - # on column break append html to section html or doc html - if df.fieldtype == "Column Break": - if sec_on and not col_on and has_data: - section_html += """ -
-
-
- {0} -
-
-
-
- {1} -
- """.format(section_label, html) - elif col_on == 1 and has_data: - section_html += "
" + html + "
" - elif col_on > 1 and has_data: - doc_html += "
" + html + "
" - else: - doc_html += """ -
-
- {0} -
-
- """.format(html) - - html = "" - col_on += 1 - - if df.label: - html += "
" + df.label - continue - - # on table iterate through items and create table - # based on the in_list_view property - # append to section html or doc html - if df.fieldtype == "Table": - items = doc.get(df.fieldname) - if not items: - continue - child_meta = frappe.get_meta(df.options) - - if not has_data: - has_data = True - table_head = table_row = "" - create_head = True - - for item in items: - table_row += "" - for cdf in child_meta.fields: - if cdf.in_list_view: - if create_head: - table_head += "" + cdf.label + "" - if item.get(cdf.fieldname): - table_row += "" + cstr(item.get(cdf.fieldname)) + "" - else: - table_row += "" - - create_head = False - table_row += "" - - if sec_on: - section_html += """ - - {0} {1} -
- """.format(table_head, table_row) - else: - html += """ - - {0} {1} -
- """.format(table_head, table_row) - continue - - # on any other field type add label and value to html - if not df.hidden and not df.print_hide and doc.get(df.fieldname) and df.fieldname not in exclude_fields: - formatted_value = format_value(doc.get(df.fieldname), meta.get_field(df.fieldname), doc) - html += "
{0} : {1}".format(df.label or df.fieldname, formatted_value) - - if not has_data : has_data = True - - if sec_on and col_on and has_data: - doc_html += section_html + html + "
" - elif sec_on and not col_on and has_data: - doc_html += """ -
-
- {0} {1} -
-
- """.format(section_html, html) - - return {"html": doc_html} - - -def update_address_links(address, method): - ''' - Hook validate Address - If Patient is linked in Address, also link the associated Customer - ''' - if 'Healthcare' not in frappe.get_active_domains(): - return - - patient_links = list(filter(lambda link: link.get('link_doctype') == 'Patient', address.links)) - - for link in patient_links: - customer = frappe.db.get_value('Patient', link.get('link_name'), 'customer') - if customer and not address.has_link('Customer', customer): - address.append('links', dict(link_doctype = 'Customer', link_name = customer)) - - -def update_patient_email_and_phone_numbers(contact, method): - ''' - Hook validate Contact - Update linked Patients' primary mobile and phone numbers - ''' - if 'Healthcare' not in frappe.get_active_domains(): - return - - if contact.is_primary_contact and (contact.email_id or contact.mobile_no or contact.phone): - patient_links = list(filter(lambda link: link.get('link_doctype') == 'Patient', contact.links)) - - for link in patient_links: - contact_details = frappe.db.get_value('Patient', link.get('link_name'), ['email', 'mobile', 'phone'], as_dict=1) - if contact.email_id and contact.email_id != contact_details.get('email'): - frappe.db.set_value('Patient', link.get('link_name'), 'email', contact.email_id) - if contact.mobile_no and contact.mobile_no != contact_details.get('mobile'): - frappe.db.set_value('Patient', link.get('link_name'), 'mobile', contact.mobile_no) - if contact.phone and contact.phone != contact_details.get('phone'): - frappe.db.set_value('Patient', link.get('link_name'), 'phone', contact.phone) diff --git a/erpnext/healthcare/web_form/__init__.py b/erpnext/healthcare/web_form/__init__.py deleted file mode 100644 index e69de29bb2d..00000000000 diff --git a/erpnext/healthcare/web_form/lab_test/__init__.py b/erpnext/healthcare/web_form/lab_test/__init__.py deleted file mode 100644 index e69de29bb2d..00000000000 diff --git a/erpnext/healthcare/web_form/lab_test/lab_test.js b/erpnext/healthcare/web_form/lab_test/lab_test.js deleted file mode 100644 index efcd8abc896..00000000000 --- a/erpnext/healthcare/web_form/lab_test/lab_test.js +++ /dev/null @@ -1,34 +0,0 @@ -frappe.ready(function() { - // bind events here - var normal_test_items = $('div[data-fieldname = "normal_test_items"]'); - var normal_test_items_add_btn = $('button[data-fieldname = "normal_test_items"]'); - var special_test_items = $('div[data-fieldname = "special_test_items"]'); - var special_test_items_add_btn = $('button[data-fieldname = "special_test_items"]'); - var sensitivity_test_items = $('div[data-fieldname = "sensitivity_test_items"]'); - var sensitivity_test_items_add_btn = $('button[data-fieldname = "sensitivity_test_items"]'); - var sensitivity_toggle = $('input[name = "sensitivity_toggle"]'); - var special_toggle = $('input[name = "special_toggle"]'); - var normal_toggle = $('input[name = "normal_toggle"]'); - if(normal_toggle.val() == 1){ - // normal_test_items[0].style.display = "none"; - // normal_test_items[0].setAttribute("hidden", true); - // normal_test_items_add_btn[0].style.visibility = "hidden"; - special_test_items[0].style.display = "none"; - special_test_items_add_btn[0].style.display = "none"; - sensitivity_test_items[0].style.display = "none"; - sensitivity_test_items_add_btn[0].style.display = "none"; - normal_test_items_add_btn[0].style.display = "none"; - }else if(sensitivity_toggle.val() == 1){ - special_test_items[0].style.display = "none"; - special_test_items_add_btn[0].style.display = "none"; - normal_test_items[0].style.display = "none"; - normal_test_items_add_btn[0].style.display = "none"; - sensitivity_test_items_add_btn[0].style.display = "none"; - }else if(special_toggle.val() == 1){ - normal_test_items[0].style.display = "none"; - normal_test_items_add_btn[0].style.display = "none"; - sensitivity_test_items[0].style.display = "none"; - sensitivity_test_items_add_btn[0].style.display = "none"; - special_test_items_add_btn[0].style.display = "none"; - } -}); diff --git a/erpnext/healthcare/web_form/lab_test/lab_test.json b/erpnext/healthcare/web_form/lab_test/lab_test.json deleted file mode 100644 index 35099174e8d..00000000000 --- a/erpnext/healthcare/web_form/lab_test/lab_test.json +++ /dev/null @@ -1,460 +0,0 @@ -{ - "accept_payment": 0, - "allow_comments": 1, - "allow_delete": 0, - "allow_edit": 1, - "allow_incomplete": 0, - "allow_multiple": 1, - "allow_print": 1, - "amount": 0.0, - "amount_based_on_field": 0, - "creation": "2017-06-06 16:12:33.052258", - "currency": "INR", - "doc_type": "Lab Test", - "docstatus": 0, - "doctype": "Web Form", - "idx": 0, - "introduction_text": "Lab Test", - "is_standard": 1, - "login_required": 1, - "max_attachment_size": 0, - "modified": "2020-06-22 12:59:49.126398", - "modified_by": "Administrator", - "module": "Healthcare", - "name": "lab-test", - "owner": "Administrator", - "payment_button_label": "Buy Now", - "print_format": "Lab Test Print", - "published": 1, - "route": "lab-test", - "route_to_success_link": 0, - "show_attachments": 0, - "show_in_grid": 0, - "show_sidebar": 1, - "sidebar_items": [], - "success_url": "/lab-test", - "title": "Lab Test", - "web_form_fields": [ - { - "allow_read_on_all_link_options": 0, - "fieldname": "lab_test_name", - "fieldtype": "Data", - "hidden": 0, - "label": "Test Name", - "max_length": 0, - "max_value": 0, - "read_only": 1, - "reqd": 0, - "show_in_filter": 0 - }, - { - "allow_read_on_all_link_options": 0, - "fieldname": "department", - "fieldtype": "Link", - "hidden": 0, - "label": "Department", - "max_length": 0, - "max_value": 0, - "options": "Medical Department", - "read_only": 1, - "reqd": 0, - "show_in_filter": 0 - }, - { - "allow_read_on_all_link_options": 0, - "fieldname": "column_break_26", - "fieldtype": "Column Break", - "hidden": 0, - "max_length": 0, - "max_value": 0, - "read_only": 0, - "reqd": 0, - "show_in_filter": 0 - }, - { - "allow_read_on_all_link_options": 0, - "fieldname": "company", - "fieldtype": "Link", - "hidden": 0, - "label": "Company", - "max_length": 0, - "max_value": 0, - "options": "Company", - "read_only": 0, - "reqd": 0, - "show_in_filter": 0 - }, - { - "allow_read_on_all_link_options": 0, - "fieldname": "status", - "fieldtype": "Select", - "hidden": 0, - "label": "Status", - "max_length": 0, - "max_value": 0, - "options": "Draft\nCompleted\nApproved\nRejected\nCancelled", - "read_only": 1, - "reqd": 0, - "show_in_filter": 0 - }, - { - "allow_read_on_all_link_options": 0, - "fieldname": "submitted_date", - "fieldtype": "Datetime", - "hidden": 0, - "label": "Submitted Date", - "max_length": 0, - "max_value": 0, - "read_only": 0, - "reqd": 0, - "show_in_filter": 0 - }, - { - "allow_read_on_all_link_options": 0, - "fieldname": "sb_first", - "fieldtype": "Section Break", - "hidden": 0, - "max_length": 0, - "max_value": 0, - "read_only": 0, - "reqd": 0, - "show_in_filter": 0 - }, - { - "allow_read_on_all_link_options": 0, - "fieldname": "patient", - "fieldtype": "Link", - "hidden": 0, - "label": "Patient", - "max_length": 0, - "max_value": 0, - "options": "Patient", - "read_only": 0, - "reqd": 1, - "show_in_filter": 0 - }, - { - "allow_read_on_all_link_options": 0, - "fieldname": "patient_name", - "fieldtype": "Data", - "hidden": 0, - "label": "Patient Name", - "max_length": 0, - "max_value": 0, - "read_only": 1, - "reqd": 0, - "show_in_filter": 0 - }, - { - "allow_read_on_all_link_options": 0, - "fieldname": "patient_age", - "fieldtype": "Data", - "hidden": 0, - "label": "Age", - "max_length": 0, - "max_value": 0, - "read_only": 1, - "reqd": 0, - "show_in_filter": 0 - }, - { - "allow_read_on_all_link_options": 0, - "fieldname": "patient_sex", - "fieldtype": "Link", - "hidden": 0, - "label": "Gender", - "max_length": 0, - "max_value": 0, - "options": "Gender", - "read_only": 0, - "reqd": 1, - "show_in_filter": 0 - }, - { - "allow_read_on_all_link_options": 0, - "fieldname": "inpatient_record", - "fieldtype": "Link", - "hidden": 0, - "label": "Inpatient Record", - "max_length": 0, - "max_value": 0, - "options": "Inpatient Record", - "read_only": 1, - "reqd": 0, - "show_in_filter": 0 - }, - { - "allow_read_on_all_link_options": 0, - "fieldname": "report_preference", - "fieldtype": "Data", - "hidden": 0, - "label": "Report Preference", - "max_length": 0, - "max_value": 0, - "read_only": 1, - "reqd": 0, - "show_in_filter": 0 - }, - { - "allow_read_on_all_link_options": 0, - "fieldname": "email", - "fieldtype": "Data", - "hidden": 1, - "label": "Email", - "max_length": 0, - "max_value": 0, - "read_only": 1, - "reqd": 0, - "show_in_filter": 0 - }, - { - "allow_read_on_all_link_options": 0, - "fieldname": "mobile", - "fieldtype": "Data", - "hidden": 1, - "label": "Mobile", - "max_length": 0, - "max_value": 0, - "read_only": 1, - "reqd": 0, - "show_in_filter": 0 - }, - { - "allow_read_on_all_link_options": 0, - "fieldname": "c_b", - "fieldtype": "Column Break", - "hidden": 0, - "max_length": 0, - "max_value": 0, - "read_only": 0, - "reqd": 0, - "show_in_filter": 0 - }, - { - "allow_read_on_all_link_options": 0, - "fieldname": "practitioner", - "fieldtype": "Link", - "hidden": 0, - "label": "Requesting Practitioner", - "max_length": 0, - "max_value": 0, - "options": "Healthcare Practitioner", - "read_only": 0, - "reqd": 0, - "show_in_filter": 0 - }, - { - "allow_read_on_all_link_options": 0, - "fieldname": "practitioner_name", - "fieldtype": "Data", - "hidden": 0, - "label": "Requesting Practitioner", - "max_length": 0, - "max_value": 0, - "read_only": 1, - "reqd": 0, - "show_in_filter": 0 - }, - { - "allow_read_on_all_link_options": 0, - "fieldname": "requesting_department", - "fieldtype": "Link", - "hidden": 0, - "label": "Requesting Department", - "max_length": 0, - "max_value": 0, - "options": "Medical Department", - "read_only": 1, - "reqd": 0, - "show_in_filter": 0 - }, - { - "allow_read_on_all_link_options": 0, - "fieldname": "employee", - "fieldtype": "Link", - "hidden": 0, - "label": "Employee (Lab Technician)", - "max_length": 0, - "max_value": 0, - "options": "Employee", - "read_only": 0, - "reqd": 0, - "show_in_filter": 0 - }, - { - "allow_read_on_all_link_options": 0, - "fieldname": "employee_name", - "fieldtype": "Data", - "hidden": 0, - "label": "Lab Technician Name", - "max_length": 0, - "max_value": 0, - "read_only": 1, - "reqd": 0, - "show_in_filter": 0 - }, - { - "allow_read_on_all_link_options": 0, - "fieldname": "employee_designation", - "fieldtype": "Data", - "hidden": 0, - "label": "Lab Technician Designation", - "max_length": 0, - "max_value": 0, - "read_only": 1, - "reqd": 0, - "show_in_filter": 0 - }, - { - "allow_read_on_all_link_options": 0, - "fieldname": "sb_normal", - "fieldtype": "Section Break", - "hidden": 0, - "max_length": 0, - "max_value": 0, - "read_only": 0, - "reqd": 0, - "show_in_filter": 0 - }, - { - "allow_read_on_all_link_options": 0, - "fieldname": "lab_test_html", - "fieldtype": "HTML", - "hidden": 0, - "max_length": 0, - "max_value": 0, - "read_only": 0, - "reqd": 0, - "show_in_filter": 0 - }, - { - "allow_read_on_all_link_options": 0, - "fieldname": "normal_test_items", - "fieldtype": "Table", - "hidden": 0, - "max_length": 0, - "max_value": 0, - "options": "Normal Test Result", - "read_only": 0, - "reqd": 0, - "show_in_filter": 0 - }, - { - "allow_read_on_all_link_options": 0, - "fieldname": "sb_descriptive", - "fieldtype": "Section Break", - "hidden": 0, - "max_length": 0, - "max_value": 0, - "read_only": 0, - "reqd": 0, - "show_in_filter": 0 - }, - { - "allow_read_on_all_link_options": 0, - "fieldname": "descriptive_test_items", - "fieldtype": "Table", - "hidden": 0, - "max_length": 0, - "max_value": 0, - "options": "Descriptive Test Result", - "read_only": 0, - "reqd": 0, - "show_in_filter": 0 - }, - { - "allow_read_on_all_link_options": 0, - "depends_on": "special_toggle", - "fieldname": "organisms_section", - "fieldtype": "Section Break", - "hidden": 0, - "max_length": 0, - "max_value": 0, - "read_only": 0, - "reqd": 0, - "show_in_filter": 0 - }, - { - "allow_read_on_all_link_options": 0, - "fieldname": "organisms", - "fieldtype": "Table", - "hidden": 0, - "max_length": 0, - "max_value": 0, - "options": "Organism Test Result", - "read_only": 0, - "reqd": 0, - "show_in_filter": 0 - }, - { - "allow_read_on_all_link_options": 0, - "fieldname": "sb_sensitivity", - "fieldtype": "Section Break", - "hidden": 0, - "max_length": 0, - "max_value": 0, - "read_only": 0, - "reqd": 0, - "show_in_filter": 0 - }, - { - "allow_read_on_all_link_options": 0, - "fieldname": "sensitivity_test_items", - "fieldtype": "Table", - "hidden": 0, - "max_length": 0, - "max_value": 0, - "options": "Sensitivity Test Result", - "read_only": 0, - "reqd": 0, - "show_in_filter": 0 - }, - { - "allow_read_on_all_link_options": 0, - "fieldname": "sb_comments", - "fieldtype": "Section Break", - "hidden": 0, - "max_length": 0, - "max_value": 0, - "read_only": 0, - "reqd": 0, - "show_in_filter": 0 - }, - { - "allow_read_on_all_link_options": 0, - "fieldname": "lab_test_comment", - "fieldtype": "Text", - "hidden": 0, - "label": "Comments", - "max_length": 0, - "max_value": 0, - "read_only": 0, - "reqd": 0, - "show_in_filter": 0 - }, - { - "allow_read_on_all_link_options": 0, - "fieldname": "sb_customresult", - "fieldtype": "Section Break", - "hidden": 0, - "label": "Custom Result", - "max_length": 0, - "max_value": 0, - "read_only": 0, - "reqd": 0, - "show_in_filter": 0 - }, - { - "allow_read_on_all_link_options": 0, - "fieldname": "custom_result", - "fieldtype": "Text Editor", - "hidden": 0, - "label": "Custom Result", - "max_length": 0, - "max_value": 0, - "read_only": 0, - "reqd": 0, - "show_in_filter": 0 - } - ] -} \ No newline at end of file diff --git a/erpnext/healthcare/web_form/lab_test/lab_test.py b/erpnext/healthcare/web_form/lab_test/lab_test.py deleted file mode 100644 index ec08985b191..00000000000 --- a/erpnext/healthcare/web_form/lab_test/lab_test.py +++ /dev/null @@ -1,26 +0,0 @@ -from __future__ import unicode_literals - -import frappe - - -def get_context(context): - context.read_only = 1 - -def get_list_context(context): - context.row_template = "erpnext/templates/includes/healthcare/lab_test_row_template.html" - context.get_list = get_lab_test_list - -def get_lab_test_list(doctype, txt, filters, limit_start, limit_page_length = 20, order_by='modified desc'): - patient = get_patient() - lab_tests = frappe.db.sql("""select * from `tabLab Test` - where patient = %s order by result_date""", patient, as_dict = True) - return lab_tests - -def get_patient(): - return frappe.get_value("Patient",{"email": frappe.session.user}, "name") - -def has_website_permission(doc, ptype, user, verbose=False): - if doc.patient == get_patient(): - return True - else: - return False diff --git a/erpnext/healthcare/web_form/patient_appointments/__init__.py b/erpnext/healthcare/web_form/patient_appointments/__init__.py deleted file mode 100644 index e69de29bb2d..00000000000 diff --git a/erpnext/healthcare/web_form/patient_appointments/patient_appointments.js b/erpnext/healthcare/web_form/patient_appointments/patient_appointments.js deleted file mode 100644 index f09e5409192..00000000000 --- a/erpnext/healthcare/web_form/patient_appointments/patient_appointments.js +++ /dev/null @@ -1,3 +0,0 @@ -frappe.ready(function() { - // bind events here -}); diff --git a/erpnext/healthcare/web_form/patient_appointments/patient_appointments.json b/erpnext/healthcare/web_form/patient_appointments/patient_appointments.json deleted file mode 100644 index e9cf7a8c97f..00000000000 --- a/erpnext/healthcare/web_form/patient_appointments/patient_appointments.json +++ /dev/null @@ -1,111 +0,0 @@ -{ - "accept_payment": 0, - "allow_comments": 0, - "allow_delete": 0, - "allow_edit": 1, - "allow_incomplete": 0, - "allow_multiple": 1, - "allow_print": 1, - "amount": 0.0, - "amount_based_on_field": 0, - "creation": "2017-06-07 15:30:44.984832", - "currency": "INR", - "doc_type": "Patient Appointment", - "docstatus": 0, - "doctype": "Web Form", - "idx": 0, - "introduction_text": "Patient Appointments", - "is_standard": 1, - "login_required": 1, - "max_attachment_size": 0, - "modified": "2018-07-16 13:11:08.626316", - "modified_by": "Administrator", - "module": "Healthcare", - "name": "patient-appointments", - "owner": "Administrator", - "payment_button_label": "Buy Now", - "published": 1, - "route": "patient-appointments", - "show_sidebar": 1, - "sidebar_items": [], - "success_url": "/patient-appointments", - "title": "Patient Appointments", - "web_form_fields": [ - { - "fieldname": "patient", - "fieldtype": "Link", - "hidden": 0, - "label": "Patient", - "max_length": 0, - "max_value": 0, - "options": "Patient", - "read_only": 0, - "reqd": 1 - }, - { - "fieldname": "practitioner", - "fieldtype": "Link", - "hidden": 0, - "label": "Healthcare Practitioner", - "max_length": 0, - "max_value": 0, - "options": "Healthcare Practitioner", - "read_only": 0, - "reqd": 1 - }, - { - "fieldname": "appointment_date", - "fieldtype": "Date", - "hidden": 0, - "label": "Date", - "max_length": 0, - "max_value": 0, - "read_only": 0, - "reqd": 1 - }, - { - "fieldname": "appointment_time", - "fieldtype": "Data", - "hidden": 0, - "label": "Time", - "max_length": 0, - "max_value": 0, - "read_only": 0, - "reqd": 0 - }, - { - "fieldname": "department", - "fieldtype": "Link", - "hidden": 0, - "label": "Department", - "max_length": 0, - "max_value": 0, - "options": "Medical Department", - "read_only": 0, - "reqd": 0 - }, - { - "fieldname": "appointment_type", - "fieldtype": "Link", - "hidden": 0, - "label": "Type", - "max_length": 0, - "max_value": 0, - "options": "Appointment Type", - "read_only": 0, - "reqd": 0 - }, - { - "default": "Scheduled", - "fieldname": "status", - "fieldtype": "Select", - "hidden": 0, - "label": "Status", - "max_length": 0, - "max_value": 0, - "options": "\nScheduled\nOpen\nClosed\nPending\nCancelled", - "read_only": 1, - "reqd": 0 - } - ] -} \ No newline at end of file diff --git a/erpnext/healthcare/web_form/patient_appointments/patient_appointments.py b/erpnext/healthcare/web_form/patient_appointments/patient_appointments.py deleted file mode 100644 index 80c12fd2144..00000000000 --- a/erpnext/healthcare/web_form/patient_appointments/patient_appointments.py +++ /dev/null @@ -1,26 +0,0 @@ -from __future__ import unicode_literals - -import frappe - - -def get_context(context): - context.read_only = 1 - -def get_list_context(context): - context.row_template = "erpnext/templates/includes/healthcare/appointment_row_template.html" - context.get_list = get_appointment_list - -def get_appointment_list(doctype, txt, filters, limit_start, limit_page_length = 20, order_by='modified desc'): - patient = get_patient() - lab_tests = frappe.db.sql("""select * from `tabPatient Appointment` - where patient = %s and (status = 'Open' or status = 'Scheduled') order by appointment_date""", patient, as_dict = True) - return lab_tests - -def get_patient(): - return frappe.get_value("Patient",{"email": frappe.session.user}, "name") - -def has_website_permission(doc, ptype, user, verbose=False): - if doc.patient == get_patient(): - return True - else: - return False diff --git a/erpnext/healthcare/web_form/patient_registration/__init__.py b/erpnext/healthcare/web_form/patient_registration/__init__.py deleted file mode 100644 index e69de29bb2d..00000000000 diff --git a/erpnext/healthcare/web_form/patient_registration/patient_registration.js b/erpnext/healthcare/web_form/patient_registration/patient_registration.js deleted file mode 100644 index f09e5409192..00000000000 --- a/erpnext/healthcare/web_form/patient_registration/patient_registration.js +++ /dev/null @@ -1,3 +0,0 @@ -frappe.ready(function() { - // bind events here -}); diff --git a/erpnext/healthcare/web_form/patient_registration/patient_registration.json b/erpnext/healthcare/web_form/patient_registration/patient_registration.json deleted file mode 100644 index 9ed92de16f5..00000000000 --- a/erpnext/healthcare/web_form/patient_registration/patient_registration.json +++ /dev/null @@ -1,397 +0,0 @@ -{ - "accept_payment": 0, - "allow_comments": 0, - "allow_delete": 0, - "allow_edit": 1, - "allow_incomplete": 0, - "allow_multiple": 0, - "allow_print": 0, - "amount": 0.0, - "amount_based_on_field": 0, - "button_label": "Register", - "creation": "2020-03-03 01:01:16.250607", - "currency": "INR", - "doc_type": "Patient", - "docstatus": 0, - "doctype": "Web Form", - "idx": 0, - "introduction_text": "", - "is_standard": 1, - "login_required": 0, - "max_attachment_size": 0, - "modified": "2020-03-26 17:25:15.361918", - "modified_by": "Administrator", - "module": "Healthcare", - "name": "patient-registration", - "owner": "Administrator", - "payment_button_label": "Buy Now", - "published": 1, - "route": "patient-registration", - "route_to_success_link": 0, - "show_attachments": 0, - "show_in_grid": 0, - "show_sidebar": 1, - "sidebar_items": [], - "success_message": "Registration Successfully. Thank You!", - "success_url": "/patient-registration", - "title": "Patient Registration", - "web_form_fields": [ - { - "allow_read_on_all_link_options": 0, - "fieldname": "basic_info", - "fieldtype": "Section Break", - "hidden": 0, - "label": "Patient Demographics", - "max_length": 0, - "max_value": 0, - "options": "fa fa-user", - "read_only": 0, - "reqd": 0, - "show_in_filter": 0 - }, - { - "allow_read_on_all_link_options": 0, - "fieldname": "first_name", - "fieldtype": "Data", - "hidden": 0, - "label": "First Name", - "max_length": 0, - "max_value": 0, - "read_only": 0, - "reqd": 1, - "show_in_filter": 0 - }, - { - "allow_read_on_all_link_options": 0, - "fieldname": "middle_name", - "fieldtype": "Data", - "hidden": 0, - "label": "Middle Name (optional)", - "max_length": 0, - "max_value": 0, - "read_only": 0, - "reqd": 0, - "show_in_filter": 0 - }, - { - "allow_read_on_all_link_options": 0, - "fieldname": "last_name", - "fieldtype": "Data", - "hidden": 0, - "label": "Last Name", - "max_length": 0, - "max_value": 0, - "read_only": 0, - "reqd": 1, - "show_in_filter": 0 - }, - { - "allow_read_on_all_link_options": 0, - "fieldname": "sex", - "fieldtype": "Link", - "hidden": 0, - "label": "Gender", - "max_length": 0, - "max_value": 0, - "options": "Gender", - "read_only": 0, - "reqd": 1, - "show_in_filter": 0 - }, - { - "allow_read_on_all_link_options": 0, - "fieldname": "blood_group", - "fieldtype": "Select", - "hidden": 0, - "label": "Blood Group", - "max_length": 0, - "max_value": 0, - "options": "\nA Positive\nA Negative\nAB Positive\nAB Negative\nB Positive\nB Negative\nO Positive\nO Negative", - "read_only": 0, - "reqd": 0, - "show_in_filter": 0 - }, - { - "allow_read_on_all_link_options": 0, - "fieldname": "", - "fieldtype": "Column Break", - "hidden": 0, - "max_length": 0, - "max_value": 0, - "read_only": 0, - "reqd": 0, - "show_in_filter": 0 - }, - { - "allow_read_on_all_link_options": 0, - "fieldname": "dob", - "fieldtype": "Date", - "hidden": 0, - "label": "Date of birth", - "max_length": 0, - "max_value": 0, - "read_only": 0, - "reqd": 0, - "show_in_filter": 0 - }, - { - "allow_read_on_all_link_options": 0, - "fieldname": "mobile", - "fieldtype": "Data", - "hidden": 0, - "label": "Mobile", - "max_length": 0, - "max_value": 0, - "read_only": 0, - "reqd": 0, - "show_in_filter": 0 - }, - { - "allow_read_on_all_link_options": 0, - "fieldname": "email", - "fieldtype": "Data", - "hidden": 0, - "label": "Email", - "max_length": 0, - "max_value": 0, - "options": "Email", - "read_only": 0, - "reqd": 0, - "show_in_filter": 0 - }, - { - "allow_read_on_all_link_options": 0, - "fieldname": "phone", - "fieldtype": "Data", - "hidden": 0, - "label": "Phone", - "max_length": 0, - "max_value": 0, - "read_only": 0, - "reqd": 0, - "show_in_filter": 0 - }, - { - "allow_read_on_all_link_options": 0, - "fieldname": "", - "fieldtype": "Section Break", - "hidden": 0, - "label": "Personal Details", - "max_length": 0, - "max_value": 0, - "read_only": 0, - "reqd": 0, - "show_in_filter": 0 - }, - { - "allow_read_on_all_link_options": 0, - "fieldname": "occupation", - "fieldtype": "Data", - "hidden": 0, - "label": "Occupation", - "max_length": 0, - "max_value": 0, - "read_only": 0, - "reqd": 0, - "show_in_filter": 0 - }, - { - "allow_read_on_all_link_options": 0, - "fieldname": "", - "fieldtype": "Column Break", - "hidden": 0, - "max_length": 0, - "max_value": 0, - "read_only": 0, - "reqd": 0, - "show_in_filter": 0 - }, - { - "allow_read_on_all_link_options": 0, - "fieldname": "marital_status", - "fieldtype": "Select", - "hidden": 0, - "label": "Marital Status", - "max_length": 0, - "max_value": 0, - "options": "\nSingle\nMarried\nDivorced\nWidow", - "read_only": 0, - "reqd": 0, - "show_in_filter": 0 - }, - { - "allow_read_on_all_link_options": 0, - "fieldname": "allergy_medical_and_surgical_history", - "fieldtype": "Section Break", - "hidden": 0, - "label": "Allergies, Medical and Surgical History", - "max_length": 0, - "max_value": 0, - "read_only": 0, - "reqd": 0, - "show_in_filter": 0 - }, - { - "allow_read_on_all_link_options": 0, - "fieldname": "allergies", - "fieldtype": "Small Text", - "hidden": 0, - "label": "Allergies", - "max_length": 0, - "max_value": 0, - "read_only": 0, - "reqd": 0, - "show_in_filter": 0 - }, - { - "allow_read_on_all_link_options": 0, - "fieldname": "medication", - "fieldtype": "Small Text", - "hidden": 0, - "label": "Medication", - "max_length": 0, - "max_value": 0, - "read_only": 0, - "reqd": 0, - "show_in_filter": 0 - }, - { - "allow_read_on_all_link_options": 0, - "fieldname": "column_break_20", - "fieldtype": "Column Break", - "hidden": 0, - "max_length": 0, - "max_value": 0, - "read_only": 0, - "reqd": 0, - "show_in_filter": 0 - }, - { - "allow_read_on_all_link_options": 0, - "fieldname": "medical_history", - "fieldtype": "Small Text", - "hidden": 0, - "label": "Medical History", - "max_length": 0, - "max_value": 0, - "read_only": 0, - "reqd": 0, - "show_in_filter": 0 - }, - { - "allow_read_on_all_link_options": 0, - "fieldname": "surgical_history", - "fieldtype": "Small Text", - "hidden": 0, - "label": "Surgical History", - "max_length": 0, - "max_value": 0, - "read_only": 0, - "reqd": 0, - "show_in_filter": 0 - }, - { - "allow_read_on_all_link_options": 0, - "fieldname": "risk_factors", - "fieldtype": "Section Break", - "hidden": 0, - "label": "Risk Factors", - "max_length": 0, - "max_value": 0, - "read_only": 0, - "reqd": 0, - "show_in_filter": 0 - }, - { - "allow_read_on_all_link_options": 0, - "default": "0", - "fieldname": "tobacco_past_use", - "fieldtype": "Check", - "hidden": 0, - "label": "Check if you have a history of Tobacco Consumption", - "max_length": 0, - "max_value": 0, - "options": "", - "read_only": 0, - "reqd": 0, - "show_in_filter": 0 - }, - { - "allow_read_on_all_link_options": 0, - "default": "0", - "fieldname": "tobacco_current_use", - "fieldtype": "Check", - "hidden": 0, - "label": "Check if you consume Tobacco", - "max_length": 0, - "max_value": 0, - "options": "", - "read_only": 0, - "reqd": 0, - "show_in_filter": 0 - }, - { - "allow_read_on_all_link_options": 0, - "default": "0", - "fieldname": "alcohol_past_use", - "fieldtype": "Check", - "hidden": 0, - "label": "Check if you have a history of Alcohol Consumption", - "max_length": 0, - "max_value": 0, - "options": "", - "read_only": 0, - "reqd": 0, - "show_in_filter": 0 - }, - { - "allow_read_on_all_link_options": 0, - "default": "0", - "fieldname": "alcohol_current_use", - "fieldtype": "Check", - "hidden": 0, - "label": "Check if you consume Alcohol", - "max_length": 0, - "max_value": 0, - "options": "", - "read_only": 0, - "reqd": 0, - "show_in_filter": 0 - }, - { - "allow_read_on_all_link_options": 0, - "fieldname": "column_break_32", - "fieldtype": "Column Break", - "hidden": 0, - "max_length": 0, - "max_value": 0, - "read_only": 0, - "reqd": 0, - "show_in_filter": 0 - }, - { - "allow_read_on_all_link_options": 0, - "fieldname": "surrounding_factors", - "fieldtype": "Small Text", - "hidden": 0, - "label": "Occupational Hazards and Environmental Factors", - "max_length": 0, - "max_value": 0, - "read_only": 0, - "reqd": 0, - "show_in_filter": 0 - }, - { - "allow_read_on_all_link_options": 0, - "fieldname": "other_risk_factors", - "fieldtype": "Small Text", - "hidden": 0, - "label": "Other Risk Factors", - "max_length": 0, - "max_value": 0, - "read_only": 0, - "reqd": 0, - "show_in_filter": 0 - } - ] -} \ No newline at end of file diff --git a/erpnext/healthcare/web_form/patient_registration/patient_registration.py b/erpnext/healthcare/web_form/patient_registration/patient_registration.py deleted file mode 100644 index f57de916dd1..00000000000 --- a/erpnext/healthcare/web_form/patient_registration/patient_registration.py +++ /dev/null @@ -1,6 +0,0 @@ -from __future__ import unicode_literals - - -def get_context(context): - # do your magic here - pass diff --git a/erpnext/healthcare/web_form/personal_details/__init__.py b/erpnext/healthcare/web_form/personal_details/__init__.py deleted file mode 100644 index e69de29bb2d..00000000000 diff --git a/erpnext/healthcare/web_form/personal_details/personal_details.js b/erpnext/healthcare/web_form/personal_details/personal_details.js deleted file mode 100644 index f09e5409192..00000000000 --- a/erpnext/healthcare/web_form/personal_details/personal_details.js +++ /dev/null @@ -1,3 +0,0 @@ -frappe.ready(function() { - // bind events here -}); diff --git a/erpnext/healthcare/web_form/personal_details/personal_details.json b/erpnext/healthcare/web_form/personal_details/personal_details.json deleted file mode 100644 index aad987aeb9e..00000000000 --- a/erpnext/healthcare/web_form/personal_details/personal_details.json +++ /dev/null @@ -1,87 +0,0 @@ -{ - "accept_payment": 0, - "allow_comments": 0, - "allow_delete": 0, - "allow_edit": 1, - "allow_incomplete": 0, - "allow_multiple": 0, - "allow_print": 0, - "amount": 0.0, - "amount_based_on_field": 0, - "creation": "2018-07-03 19:33:23.332661", - "currency": "INR", - "doc_type": "Patient", - "docstatus": 0, - "doctype": "Web Form", - "idx": 0, - "introduction_text": "", - "is_standard": 1, - "login_required": 1, - "max_attachment_size": 0, - "modified": "2018-07-04 17:22:28.936442", - "modified_by": "Administrator", - "module": "Healthcare", - "name": "personal-details", - "owner": "Administrator", - "payment_button_label": "Buy Now", - "published": 1, - "route": "personal-details", - "show_sidebar": 1, - "sidebar_items": [], - "success_url": "/personal-details", - "title": "Personal Details", - "web_form_fields": [ - { - "fieldname": "patient_name", - "fieldtype": "Data", - "hidden": 0, - "label": "Full Name", - "max_length": 0, - "max_value": 0, - "read_only": 0, - "reqd": 1 - }, - { - "fieldname": "sex", - "fieldtype": "Select", - "hidden": 0, - "label": "Gender", - "max_length": 0, - "max_value": 0, - "options": "\nMale\nFemale\nOther", - "read_only": 0, - "reqd": 1 - }, - { - "fieldname": "dob", - "fieldtype": "Date", - "hidden": 0, - "label": "Date of birth", - "max_length": 0, - "max_value": 0, - "read_only": 0, - "reqd": 1 - }, - { - "fieldname": "mobile", - "fieldtype": "Data", - "hidden": 0, - "label": "Mobile", - "max_length": 0, - "max_value": 0, - "read_only": 0, - "reqd": 0 - }, - { - "fieldname": "email", - "fieldtype": "Data", - "hidden": 0, - "label": "Email", - "max_length": 0, - "max_value": 0, - "options": "Email", - "read_only": 1, - "reqd": 0 - } - ] -} diff --git a/erpnext/healthcare/web_form/personal_details/personal_details.py b/erpnext/healthcare/web_form/personal_details/personal_details.py deleted file mode 100644 index fe46d7b22d7..00000000000 --- a/erpnext/healthcare/web_form/personal_details/personal_details.py +++ /dev/null @@ -1,27 +0,0 @@ -from __future__ import unicode_literals - -import frappe -from frappe import _ - -no_cache = 1 - -def get_context(context): - if frappe.session.user=='Guest': - frappe.throw(_("You need to be logged in to access this page"), frappe.PermissionError) - - context.show_sidebar=True - - if frappe.db.exists("Patient", {'email': frappe.session.user}): - patient = frappe.get_doc("Patient", {'email': frappe.session.user}) - context.doc = patient - frappe.form_dict.new = 0 - frappe.form_dict.name = patient.name - -def get_patient(): - return frappe.get_value("Patient",{"email": frappe.session.user}, "name") - -def has_website_permission(doc, ptype, user, verbose=False): - if doc.name == get_patient(): - return True - else: - return False diff --git a/erpnext/healthcare/web_form/prescription/__init__.py b/erpnext/healthcare/web_form/prescription/__init__.py deleted file mode 100644 index e69de29bb2d..00000000000 diff --git a/erpnext/healthcare/web_form/prescription/prescription.js b/erpnext/healthcare/web_form/prescription/prescription.js deleted file mode 100644 index f09e5409192..00000000000 --- a/erpnext/healthcare/web_form/prescription/prescription.js +++ /dev/null @@ -1,3 +0,0 @@ -frappe.ready(function() { - // bind events here -}); diff --git a/erpnext/healthcare/web_form/prescription/prescription.json b/erpnext/healthcare/web_form/prescription/prescription.json deleted file mode 100644 index 8e19e325edd..00000000000 --- a/erpnext/healthcare/web_form/prescription/prescription.json +++ /dev/null @@ -1,120 +0,0 @@ -{ - "accept_payment": 0, - "allow_comments": 0, - "allow_delete": 0, - "allow_edit": 1, - "allow_incomplete": 0, - "allow_multiple": 1, - "allow_print": 1, - "amount": 0.0, - "amount_based_on_field": 0, - "creation": "2017-06-06 17:13:19.101374", - "currency": "INR", - "doc_type": "Patient Encounter", - "docstatus": 0, - "doctype": "Web Form", - "idx": 0, - "introduction_text": "Patient Prescriptions", - "is_standard": 1, - "login_required": 1, - "max_attachment_size": 0, - "modified": "2018-09-04 11:53:40.954517", - "modified_by": "Administrator", - "module": "Healthcare", - "name": "prescription", - "owner": "Administrator", - "payment_button_label": "Buy Now", - "print_format": "Encounter Print", - "published": 1, - "route": "prescription", - "show_in_grid": 0, - "show_sidebar": 1, - "sidebar_items": [], - "success_url": "/prescription", - "title": "Prescription", - "web_form_fields": [ - { - "fieldname": "practitioner", - "fieldtype": "Link", - "hidden": 0, - "label": "Healthcare Practitioner", - "max_length": 0, - "max_value": 0, - "options": "Healthcare Practitioner", - "read_only": 0, - "reqd": 1, - "show_in_filter": 0 - }, - { - "fieldname": "visit_department", - "fieldtype": "Link", - "hidden": 0, - "label": "Department", - "max_length": 0, - "max_value": 0, - "options": "Medical Department", - "read_only": 0, - "reqd": 0, - "show_in_filter": 0 - }, - { - "default": "Today", - "fieldname": "encounter_date", - "fieldtype": "Date", - "hidden": 0, - "label": "Encounter Date", - "max_length": 0, - "max_value": 0, - "read_only": 0, - "reqd": 1, - "show_in_filter": 0 - }, - { - "default": "", - "fieldname": "encounter_time", - "fieldtype": "Data", - "hidden": 0, - "label": "Encounter Time", - "max_length": 0, - "max_value": 0, - "read_only": 0, - "reqd": 1, - "show_in_filter": 0 - }, - { - "fieldname": "drug_prescription", - "fieldtype": "Table", - "hidden": 0, - "label": "Drug Prescription", - "max_length": 0, - "max_value": 0, - "options": "Drug Prescription", - "read_only": 0, - "reqd": 0, - "show_in_filter": 0 - }, - { - "fieldname": "lab_test_prescription", - "fieldtype": "Table", - "hidden": 0, - "label": "Investigations", - "max_length": 0, - "max_value": 0, - "options": "Lab Prescription", - "read_only": 0, - "reqd": 0, - "show_in_filter": 0 - }, - { - "fieldname": "encounter_comment", - "fieldtype": "Small Text", - "hidden": 0, - "label": "Review Details", - "max_length": 0, - "max_value": 0, - "read_only": 0, - "reqd": 0, - "show_in_filter": 0 - } - ] -} \ No newline at end of file diff --git a/erpnext/healthcare/web_form/prescription/prescription.py b/erpnext/healthcare/web_form/prescription/prescription.py deleted file mode 100644 index f6f273ad580..00000000000 --- a/erpnext/healthcare/web_form/prescription/prescription.py +++ /dev/null @@ -1,26 +0,0 @@ -from __future__ import unicode_literals - -import frappe - - -def get_context(context): - context.read_only = 1 - -def get_list_context(context): - context.row_template = "erpnext/templates/includes/healthcare/prescription_row_template.html" - context.get_list = get_encounter_list - -def get_encounter_list(doctype, txt, filters, limit_start, limit_page_length = 20, order_by='modified desc'): - patient = get_patient() - encounters = frappe.db.sql("""select * from `tabPatient Encounter` - where patient = %s order by creation desc""", patient, as_dict = True) - return encounters - -def get_patient(): - return frappe.get_value("Patient",{"email": frappe.session.user}, "name") - -def has_website_permission(doc, ptype, user, verbose=False): - if doc.patient == get_patient(): - return True - else: - return False diff --git a/erpnext/healthcare/workspace/healthcare/healthcare.json b/erpnext/healthcare/workspace/healthcare/healthcare.json deleted file mode 100644 index f69604c099c..00000000000 --- a/erpnext/healthcare/workspace/healthcare/healthcare.json +++ /dev/null @@ -1,626 +0,0 @@ -{ - "category": "", - "charts": [ - { - "chart_name": "Patient Appointments", - "label": "Patient Appointments" - } - ], - "charts_label": "", - "content": "[{\"type\": \"onboarding\", \"data\": {\"onboarding_name\":\"Healthcare\", \"col\": 12}}, {\"type\": \"chart\", \"data\": {\"chart_name\": \"Patient Appointments\", \"col\": 12}}, {\"type\": \"spacer\", \"data\": {\"col\": 12}}, {\"type\": \"header\", \"data\": {\"text\": \"Your Shortcuts\", \"level\": 4, \"col\": 12}}, {\"type\": \"shortcut\", \"data\": {\"shortcut_name\": \"Patient Appointment\", \"col\": 4}}, {\"type\": \"shortcut\", \"data\": {\"shortcut_name\": \"Patient\", \"col\": 4}}, {\"type\": \"shortcut\", \"data\": {\"shortcut_name\": \"Healthcare Service Unit\", \"col\": 4}}, {\"type\": \"shortcut\", \"data\": {\"shortcut_name\": \"Healthcare Practitioner\", \"col\": 4}}, {\"type\": \"shortcut\", \"data\": {\"shortcut_name\": \"Patient History\", \"col\": 4}}, {\"type\": \"shortcut\", \"data\": {\"shortcut_name\": \"Dashboard\", \"col\": 4}}, {\"type\": \"spacer\", \"data\": {\"col\": 12}}, {\"type\": \"header\", \"data\": {\"text\": \"Reports & Masters\", \"level\": 4, \"col\": 12}}, {\"type\": \"card\", \"data\": {\"card_name\": \"Masters\", \"col\": 4}}, {\"type\": \"card\", \"data\": {\"card_name\": \"Consultation Setup\", \"col\": 4}}, {\"type\": \"card\", \"data\": {\"card_name\": \"Consultation\", \"col\": 4}}, {\"type\": \"card\", \"data\": {\"card_name\": \"Facility Management\", \"col\": 4}}, {\"type\": \"card\", \"data\": {\"card_name\": \"Settings\", \"col\": 4}}, {\"type\": \"card\", \"data\": {\"card_name\": \"Inpatient\", \"col\": 4}}, {\"type\": \"card\", \"data\": {\"card_name\": \"Laboratory Setup\", \"col\": 4}}, {\"type\": \"card\", \"data\": {\"card_name\": \"Laboratory\", \"col\": 4}}, {\"type\": \"card\", \"data\": {\"card_name\": \"Rehabilitation and Physiotherapy\", \"col\": 4}}, {\"type\": \"card\", \"data\": {\"card_name\": \"Records and History\", \"col\": 4}}, {\"type\": \"card\", \"data\": {\"card_name\": \"Reports\", \"col\": 4}}]", - "creation": "2020-03-02 17:23:17.919682", - "developer_mode_only": 0, - "disable_user_customization": 0, - "docstatus": 0, - "doctype": "Workspace", - "extends": "", - "extends_another_page": 0, - "for_user": "", - "hide_custom": 0, - "icon": "healthcare", - "idx": 0, - "is_default": 0, - "is_standard": 0, - "label": "Healthcare", - "links": [ - { - "hidden": 0, - "is_query_report": 0, - "label": "Masters", - "link_count": 0, - "onboard": 0, - "type": "Card Break" - }, - { - "dependencies": "", - "hidden": 0, - "is_query_report": 0, - "label": "Patient", - "link_count": 0, - "link_to": "Patient", - "link_type": "DocType", - "onboard": 1, - "type": "Link" - }, - { - "dependencies": "", - "hidden": 0, - "is_query_report": 0, - "label": "Healthcare Practitioner", - "link_count": 0, - "link_to": "Healthcare Practitioner", - "link_type": "DocType", - "onboard": 1, - "type": "Link" - }, - { - "dependencies": "", - "hidden": 0, - "is_query_report": 0, - "label": "Practitioner Schedule", - "link_count": 0, - "link_to": "Practitioner Schedule", - "link_type": "DocType", - "onboard": 1, - "type": "Link" - }, - { - "dependencies": "", - "hidden": 0, - "is_query_report": 0, - "label": "Medical Department", - "link_count": 0, - "link_to": "Medical Department", - "link_type": "DocType", - "onboard": 0, - "type": "Link" - }, - { - "hidden": 0, - "is_query_report": 0, - "label": "Consultation Setup", - "onboard": 0, - "type": "Card Break" - }, - { - "dependencies": "", - "hidden": 0, - "is_query_report": 0, - "label": "Appointment Type", - "link_to": "Appointment Type", - "link_type": "DocType", - "onboard": 0, - "type": "Link" - }, - { - "dependencies": "", - "hidden": 0, - "is_query_report": 0, - "label": "Clinical Procedure Template", - "link_to": "Clinical Procedure Template", - "link_type": "DocType", - "onboard": 0, - "type": "Link" - }, - { - "dependencies": "", - "hidden": 0, - "is_query_report": 0, - "label": "Prescription Dosage", - "link_to": "Prescription Dosage", - "link_type": "DocType", - "onboard": 0, - "type": "Link" - }, - { - "dependencies": "", - "hidden": 0, - "is_query_report": 0, - "label": "Prescription Duration", - "link_to": "Prescription Duration", - "link_type": "DocType", - "onboard": 0, - "type": "Link" - }, - { - "dependencies": "", - "hidden": 0, - "is_query_report": 0, - "label": "Antibiotic", - "link_to": "Antibiotic", - "link_type": "DocType", - "onboard": 0, - "type": "Link" - }, - { - "dependencies": "", - "hidden": 0, - "is_query_report": 0, - "label": "Complaint", - "link_to": "Complaint", - "link_type": "DocType", - "onboard": 0, - "type": "Link" - }, - { - "dependencies": "", - "hidden": 0, - "is_query_report": 0, - "label": "Diagnosis", - "link_to": "Diagnosis", - "link_type": "DocType", - "onboard": 0, - "type": "Link" - }, - { - "hidden": 0, - "is_query_report": 0, - "label": "Consultation", - "onboard": 0, - "type": "Card Break" - }, - { - "dependencies": "", - "hidden": 0, - "is_query_report": 0, - "label": "Patient Appointment", - "link_to": "Patient Appointment", - "link_type": "DocType", - "onboard": 0, - "type": "Link" - }, - { - "dependencies": "", - "hidden": 0, - "is_query_report": 0, - "label": "Clinical Procedure", - "link_to": "Clinical Procedure", - "link_type": "DocType", - "onboard": 0, - "type": "Link" - }, - { - "dependencies": "", - "hidden": 0, - "is_query_report": 0, - "label": "Patient Encounter", - "link_to": "Patient Encounter", - "link_type": "DocType", - "onboard": 0, - "type": "Link" - }, - { - "dependencies": "", - "hidden": 0, - "is_query_report": 0, - "label": "Vital Signs", - "link_to": "Vital Signs", - "link_type": "DocType", - "onboard": 0, - "type": "Link" - }, - { - "dependencies": "", - "hidden": 0, - "is_query_report": 0, - "label": "Fee Validity", - "link_to": "Fee Validity", - "link_type": "DocType", - "onboard": 0, - "type": "Link" - }, - { - "hidden": 0, - "is_query_report": 0, - "label": "Facility Management", - "link_type": "DocType", - "onboard": 0, - "type": "Card Break" - }, - { - "dependencies": "", - "hidden": 0, - "is_query_report": 0, - "label": "Healthcare Service Unit Type", - "link_to": "Healthcare Service Unit Type", - "link_type": "DocType", - "onboard": 0, - "type": "Link" - }, - { - "dependencies": "", - "hidden": 0, - "is_query_report": 0, - "label": "Healthcare Service Unit", - "link_to": "Healthcare Service Unit", - "link_type": "DocType", - "onboard": 0, - "type": "Link" - }, - { - "hidden": 0, - "is_query_report": 0, - "label": "Medical Coding", - "link_type": "DocType", - "onboard": 0, - "type": "Card Break" - }, - { - "dependencies": "", - "hidden": 0, - "is_query_report": 0, - "label": "Medical Code Standard", - "link_to": "Medical Code Standard", - "link_type": "DocType", - "onboard": 0, - "type": "Link" - }, - { - "dependencies": "", - "hidden": 0, - "is_query_report": 0, - "label": "Medical Code", - "link_to": "Medical Code", - "link_type": "DocType", - "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": "Healthcare Settings", - "link_count": 0, - "link_to": "Healthcare Settings", - "link_type": "DocType", - "onboard": 1, - "type": "Link" - }, - { - "hidden": 0, - "is_query_report": 0, - "label": "Laboratory Setup", - "link_count": 0, - "onboard": 0, - "type": "Card Break" - }, - { - "dependencies": "", - "hidden": 0, - "is_query_report": 0, - "label": "Lab Test Template", - "link_count": 0, - "link_to": "Lab Test Template", - "link_type": "DocType", - "onboard": 0, - "type": "Link" - }, - { - "dependencies": "", - "hidden": 0, - "is_query_report": 0, - "label": "Lab Test Sample", - "link_count": 0, - "link_to": "Lab Test Sample", - "link_type": "DocType", - "onboard": 0, - "type": "Link" - }, - { - "dependencies": "", - "hidden": 0, - "is_query_report": 0, - "label": "Lab Test UOM", - "link_count": 0, - "link_to": "Lab Test UOM", - "link_type": "DocType", - "onboard": 0, - "type": "Link" - }, - { - "dependencies": "", - "hidden": 0, - "is_query_report": 0, - "label": "Sensitivity", - "link_count": 0, - "link_to": "Sensitivity", - "link_type": "DocType", - "onboard": 0, - "type": "Link" - }, - { - "dependencies": "", - "hidden": 0, - "is_query_report": 0, - "label": "Dosage Form", - "link_to": "Dosage Form", - "link_type": "DocType", - "onboard": 0, - "type": "Link" - }, - { - "hidden": 0, - "is_query_report": 0, - "label": "Laboratory", - "link_count": 0, - "onboard": 0, - "type": "Card Break" - }, - { - "dependencies": "", - "hidden": 0, - "is_query_report": 0, - "label": "Lab Test", - "link_count": 0, - "link_to": "Lab Test", - "link_type": "DocType", - "onboard": 0, - "type": "Link" - }, - { - "dependencies": "", - "hidden": 0, - "is_query_report": 0, - "label": "Sample Collection", - "link_count": 0, - "link_to": "Sample Collection", - "link_type": "DocType", - "onboard": 0, - "type": "Link" - }, - { - "hidden": 0, - "is_query_report": 0, - "label": "Inpatient", - "link_type": "DocType", - "onboard": 0, - "type": "Card Break" - }, - { - "hidden": 0, - "is_query_report": 0, - "label": "Inpatient Medication Order", - "link_to": "Inpatient Medication Order", - "link_type": "DocType", - "onboard": 0, - "type": "Link" - }, - { - "hidden": 0, - "is_query_report": 0, - "label": "Inpatient Record", - "link_to": "Inpatient Record", - "link_type": "DocType", - "onboard": 0, - "type": "Link" - }, - { - "hidden": 0, - "is_query_report": 0, - "label": "Inpatient Medication Entry", - "link_to": "Inpatient Medication Entry", - "link_type": "DocType", - "onboard": 0, - "type": "Link" - }, - { - "hidden": 0, - "is_query_report": 0, - "label": "Rehabilitation and Physiotherapy", - "link_count": 0, - "onboard": 0, - "type": "Card Break" - }, - { - "dependencies": "", - "hidden": 0, - "is_query_report": 0, - "label": "Exercise Type", - "link_count": 0, - "link_to": "Exercise Type", - "link_type": "DocType", - "onboard": 1, - "type": "Link" - }, - { - "dependencies": "", - "hidden": 0, - "is_query_report": 0, - "label": "Therapy Type", - "link_count": 0, - "link_to": "Therapy Type", - "link_type": "DocType", - "onboard": 1, - "type": "Link" - }, - { - "dependencies": "", - "hidden": 0, - "is_query_report": 0, - "label": "Therapy Plan", - "link_count": 0, - "link_to": "Therapy Plan", - "link_type": "DocType", - "onboard": 0, - "type": "Link" - }, - { - "dependencies": "", - "hidden": 0, - "is_query_report": 0, - "label": "Therapy Session", - "link_count": 0, - "link_to": "Therapy Session", - "link_type": "DocType", - "onboard": 0, - "type": "Link" - }, - { - "dependencies": "", - "hidden": 0, - "is_query_report": 0, - "label": "Patient Assessment Template", - "link_count": 0, - "link_to": "Patient Assessment Template", - "link_type": "DocType", - "onboard": 0, - "type": "Link" - }, - { - "dependencies": "", - "hidden": 0, - "is_query_report": 0, - "label": "Patient Assessment", - "link_count": 0, - "link_to": "Patient Assessment", - "link_type": "DocType", - "onboard": 0, - "type": "Link" - }, - { - "hidden": 0, - "is_query_report": 0, - "label": "Records and History", - "link_count": 0, - "onboard": 0, - "type": "Card Break" - }, - { - "dependencies": "", - "hidden": 0, - "is_query_report": 0, - "label": "Patient History", - "link_count": 0, - "link_to": "patient_history", - "link_type": "Page", - "onboard": 0, - "type": "Link" - }, - { - "dependencies": "", - "hidden": 0, - "is_query_report": 0, - "label": "Patient Progress", - "link_count": 0, - "link_to": "patient-progress", - "link_type": "Page", - "onboard": 0, - "type": "Link" - }, - { - "dependencies": "", - "hidden": 0, - "is_query_report": 0, - "label": "Patient Medical Record", - "link_count": 0, - "link_to": "Patient Medical Record", - "link_type": "DocType", - "onboard": 0, - "type": "Link" - }, - { - "dependencies": "", - "hidden": 0, - "is_query_report": 0, - "label": "Inpatient Record", - "link_count": 0, - "link_to": "Inpatient Record", - "link_type": "DocType", - "onboard": 0, - "type": "Link" - }, - { - "hidden": 0, - "is_query_report": 0, - "label": "Reports", - "link_count": 0, - "onboard": 0, - "type": "Card Break" - }, - { - "dependencies": "", - "hidden": 0, - "is_query_report": 1, - "label": "Patient Appointment Analytics", - "link_count": 0, - "link_to": "Patient Appointment Analytics", - "link_type": "Report", - "onboard": 0, - "type": "Link" - }, - { - "dependencies": "", - "hidden": 0, - "is_query_report": 1, - "label": "Lab Test Report", - "link_count": 0, - "link_to": "Lab Test Report", - "link_type": "Report", - "onboard": 0, - "type": "Link" - } - ], - "modified": "2021-08-30 17:37:45.316999", - "modified_by": "Administrator", - "module": "Healthcare", - "name": "Healthcare", - "onboarding": "Healthcare", - "owner": "Administrator", - "parent_page": "", - "pin_to_bottom": 0, - "pin_to_top": 0, - "public": 1, - "restrict_to_domain": "Healthcare", - "roles": [], - "sequence_id": 13, - "shortcuts": [ - { - "color": "Orange", - "format": "{} Open", - "label": "Patient Appointment", - "link_to": "Patient Appointment", - "stats_filter": "{\n \"status\": \"Open\",\n \"company\": [\"like\", '%' + frappe.defaults.get_global_default(\"company\") + '%']\n}", - "type": "DocType" - }, - { - "color": "Orange", - "format": "{} Active", - "label": "Patient", - "link_to": "Patient", - "stats_filter": "{\n \"status\": \"Active\"\n}", - "type": "DocType" - }, - { - "color": "Green", - "format": "{} Vacant", - "label": "Healthcare Service Unit", - "link_to": "Healthcare Service Unit", - "stats_filter": "{\n \"occupancy_status\": \"Vacant\",\n \"is_group\": 0,\n \"company\": [\"like\", \"%\" + frappe.defaults.get_global_default(\"company\") + \"%\"]\n}", - "type": "DocType" - }, - { - "label": "Healthcare Practitioner", - "link_to": "Healthcare Practitioner", - "type": "DocType" - }, - { - "label": "Patient History", - "link_to": "patient_history", - "type": "Page" - }, - { - "label": "Dashboard", - "link_to": "Healthcare", - "type": "Dashboard" - } - ], - "title": "Healthcare" -} \ No newline at end of file diff --git a/erpnext/hooks.py b/erpnext/hooks.py index 5b6e1eeafcd..e8aac1d1990 100644 --- a/erpnext/hooks.py +++ b/erpnext/hooks.py @@ -1,5 +1,3 @@ -from __future__ import unicode_literals - from frappe import _ app_name = "erpnext" @@ -62,6 +60,7 @@ treeviews = ['Account', 'Cost Center', 'Warehouse', 'Item Group', 'Customer Grou # website update_website_context = ["erpnext.shopping_cart.utils.update_website_context", "erpnext.education.doctype.education_settings.education_settings.update_website_context"] my_account_context = "erpnext.shopping_cart.utils.update_my_account_context" +webform_list_context = "erpnext.controllers.website_list_for_contact.get_webform_list_context" calendars = ["Task", "Work Order", "Leave Application", "Sales Order", "Holiday List", "Course Schedule"] @@ -69,7 +68,6 @@ domains = { 'Agriculture': 'erpnext.domains.agriculture', 'Distribution': 'erpnext.domains.distribution', 'Education': 'erpnext.domains.education', - 'Healthcare': 'erpnext.domains.healthcare', 'Hospitality': 'erpnext.domains.hospitality', 'Manufacturing': 'erpnext.domains.manufacturing', 'Non Profit': 'erpnext.domains.non_profit', @@ -81,7 +79,7 @@ website_generators = ["Item Group", "Item", "BOM", "Sales Partner", "Job Opening", "Student Admission"] website_context = { - "favicon": "/assets/erpnext/images/erpnext-favicon.svg", + "favicon": "/assets/erpnext/images/erpnext-favicon.svg", "splash_image": "/assets/erpnext/images/erpnext-logo.svg" } @@ -164,7 +162,6 @@ website_route_rules = [ ] standard_portal_menu_items = [ - {"title": _("Personal Details"), "route": "/personal-details", "reference_doctype": "Patient", "role": "Patient"}, {"title": _("Projects"), "route": "/project", "reference_doctype": "Project"}, {"title": _("Request for Quotations"), "route": "/rfq", "reference_doctype": "Request for Quotation", "role": "Supplier"}, {"title": _("Supplier Quotation"), "route": "/supplier-quotations", "reference_doctype": "Supplier Quotation", "role": "Supplier"}, @@ -177,9 +174,6 @@ standard_portal_menu_items = [ {"title": _("Issues"), "route": "/issues", "reference_doctype": "Issue", "role":"Customer"}, {"title": _("Addresses"), "route": "/addresses", "reference_doctype": "Address"}, {"title": _("Timesheets"), "route": "/timesheets", "reference_doctype": "Timesheet", "role":"Customer"}, - {"title": _("Lab Test"), "route": "/lab-test", "reference_doctype": "Lab Test", "role":"Patient"}, - {"title": _("Prescription"), "route": "/prescription", "reference_doctype": "Patient Encounter", "role":"Patient"}, - {"title": _("Patient Appointment"), "route": "/patient-appointments", "reference_doctype": "Patient Appointment", "role":"Patient"}, {"title": _("Fees"), "route": "/fees", "reference_doctype": "Fees", "role":"Student"}, {"title": _("Newsletter"), "route": "/newsletters", "reference_doctype": "Newsletter"}, {"title": _("Admission"), "route": "/admissions", "reference_doctype": "Student Admission", "role": "Student"}, @@ -214,10 +208,6 @@ has_website_permission = { "Delivery Note": "erpnext.controllers.website_list_for_contact.has_website_permission", "Issue": "erpnext.support.doctype.issue.issue.has_website_permission", "Timesheet": "erpnext.controllers.website_list_for_contact.has_website_permission", - "Lab Test": "erpnext.healthcare.web_form.lab_test.lab_test.has_website_permission", - "Patient Encounter": "erpnext.healthcare.web_form.prescription.prescription.has_website_permission", - "Patient Appointment": "erpnext.healthcare.web_form.patient_appointments.patient_appointments.has_website_permission", - "Patient": "erpnext.healthcare.web_form.personal_details.personal_details.has_website_permission" } dump_report_map = "erpnext.startup.report_data_map.data_map" @@ -226,15 +216,11 @@ before_tests = "erpnext.setup.utils.before_tests" standard_queries = { "Customer": "erpnext.selling.doctype.customer.customer.get_customer_list", - "Healthcare Practitioner": "erpnext.healthcare.doctype.healthcare_practitioner.healthcare_practitioner.get_practitioner_list" } doc_events = { "*": { "validate": "erpnext.support.doctype.service_level_agreement.service_level_agreement.apply", - "on_submit": "erpnext.healthcare.doctype.patient_history_settings.patient_history_settings.create_medical_record", - "on_update_after_submit": "erpnext.healthcare.doctype.patient_history_settings.patient_history_settings.update_medical_record", - "on_cancel": "erpnext.healthcare.doctype.patient_history_settings.patient_history_settings.delete_medical_record" }, "Stock Entry": { "on_submit": "erpnext.stock.doctype.material_request.material_request.update_completed_and_requested_qty", @@ -262,6 +248,7 @@ doc_events = { "validate": "erpnext.regional.india.utils.validate_tax_category" }, "Sales Invoice": { + "after_insert": "erpnext.regional.saudi_arabia.utils.create_qr_code", "on_submit": [ "erpnext.regional.create_transaction_log", "erpnext.regional.italy.utils.sales_invoice_on_submit", @@ -271,7 +258,10 @@ doc_events = { "erpnext.regional.italy.utils.sales_invoice_on_cancel", "erpnext.erpnext_integrations.taxjar_integration.delete_transaction" ], - "on_trash": "erpnext.regional.check_deletion_permission", + "on_trash": [ + "erpnext.regional.check_deletion_permission", + "erpnext.regional.saudi_arabia.utils.delete_qr_code_file" + ], "validate": [ "erpnext.regional.india.utils.validate_document_name", "erpnext.regional.india.utils.update_taxable_values" @@ -296,7 +286,6 @@ doc_events = { 'erpnext.regional.india.utils.validate_gstin_for_india', 'erpnext.regional.italy.utils.set_state_code', 'erpnext.regional.india.utils.update_gst_category', - 'erpnext.healthcare.utils.update_address_links' ], }, 'Supplier': { @@ -308,7 +297,7 @@ doc_events = { "Contact": { "on_trash": "erpnext.support.doctype.issue.issue.update_issue", "after_insert": "erpnext.telephony.doctype.call_log.call_log.link_existing_conversations", - "validate": ["erpnext.crm.utils.update_lead_phone_numbers", "erpnext.healthcare.utils.update_patient_email_and_phone_numbers"] + "validate": ["erpnext.crm.utils.update_lead_phone_numbers"] }, "Email Unsubscribe": { "after_insert": "erpnext.crm.doctype.email_campaign.email_campaign.unsubscribe_recipient" @@ -317,7 +306,8 @@ doc_events = { 'validate': ["erpnext.erpnext_integrations.taxjar_integration.set_sales_tax"] }, "Company": { - "on_trash": "erpnext.regional.india.utils.delete_gst_settings_for_company" + "on_trash": ["erpnext.regional.india.utils.delete_gst_settings_for_company", + "erpnext.regional.saudi_arabia.utils.delete_vat_settings_for_company"] }, "Integration Request": { "validate": "erpnext.accounts.doctype.payment_request.payment_request.validate_payment" @@ -329,7 +319,6 @@ doc_events = { # if payment entry not in auto cancel exempted doctypes it will cancel payment entry. auto_cancel_exempted_doctypes= [ "Payment Entry", - "Inpatient Medication Entry" ] after_migrate = ["erpnext.setup.install.update_select_perm_after_install"] @@ -342,7 +331,7 @@ scheduler_events = { }, "all": [ "erpnext.projects.doctype.project.project.project_status_update_reminder", - "erpnext.healthcare.doctype.patient_appointment.patient_appointment.send_appointment_reminder", + "erpnext.hr.doctype.interview.interview.send_interview_reminder", "erpnext.crm.doctype.social_media_post.social_media_post.process_scheduled_social_media_posts" ], "hourly": [ @@ -383,10 +372,10 @@ scheduler_events = { "erpnext.crm.doctype.email_campaign.email_campaign.send_email_to_leads_or_contacts", "erpnext.crm.doctype.email_campaign.email_campaign.set_email_campaign_status", "erpnext.selling.doctype.quotation.quotation.set_expired_status", - "erpnext.healthcare.doctype.patient_appointment.patient_appointment.update_appointment_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.non_profit.doctype.membership.membership.set_expired_status" + "erpnext.hr.doctype.interview.interview.send_daily_feedback_reminder" ], "daily_long": [ "erpnext.setup.doctype.email_digest.email_digest.send", @@ -441,7 +430,7 @@ accounting_dimension_doctypes = ["GL Entry", "Sales Invoice", "Purchase Invoice" "Purchase Receipt Item", "Stock Entry Detail", "Payment Entry Deduction", "Sales Taxes and Charges", "Purchase Taxes and Charges", "Shipping Rule", "Landed Cost Item", "Asset Value Adjustment", "Loyalty Program", "Fee Schedule", "Fee Structure", "Stock Reconciliation", "Travel Request", "Fees", "POS Profile", "Opening Invoice Creation Tool", "Opening Invoice Creation Tool Item", "Subscription", - "Subscription Plan" + "Subscription Plan", "POS Invoice", "POS Invoice Item" ] regional_overrides = { @@ -536,32 +525,6 @@ global_search_doctypes = { {"doctype": "Maintenance Visit", "index": 46}, {"doctype": "Warranty Claim", "index": 47}, ], - "Healthcare": [ - {'doctype': 'Patient', 'index': 1}, - {'doctype': 'Medical Department', 'index': 2}, - {'doctype': 'Vital Signs', 'index': 3}, - {'doctype': 'Healthcare Practitioner', 'index': 4}, - {'doctype': 'Patient Appointment', 'index': 5}, - {'doctype': 'Healthcare Service Unit', 'index': 6}, - {'doctype': 'Patient Encounter', 'index': 7}, - {'doctype': 'Antibiotic', 'index': 8}, - {'doctype': 'Diagnosis', 'index': 9}, - {'doctype': 'Lab Test', 'index': 10}, - {'doctype': 'Clinical Procedure', 'index': 11}, - {'doctype': 'Inpatient Record', 'index': 12}, - {'doctype': 'Sample Collection', 'index': 13}, - {'doctype': 'Patient Medical Record', 'index': 14}, - {'doctype': 'Appointment Type', 'index': 15}, - {'doctype': 'Fee Validity', 'index': 16}, - {'doctype': 'Practitioner Schedule', 'index': 17}, - {'doctype': 'Dosage Form', 'index': 18}, - {'doctype': 'Lab Test Sample', 'index': 19}, - {'doctype': 'Prescription Duration', 'index': 20}, - {'doctype': 'Prescription Dosage', 'index': 21}, - {'doctype': 'Sensitivity', 'index': 22}, - {'doctype': 'Complaint', 'index': 23}, - {'doctype': 'Medical Code', 'index': 24}, - ], "Education": [ {'doctype': 'Article', 'index': 1}, {'doctype': 'Video', 'index': 2}, diff --git a/erpnext/hotels/doctype/hotel_room/hotel_room.py b/erpnext/hotels/doctype/hotel_room/hotel_room.py index 93a62c98e79..e4bd1c88462 100644 --- a/erpnext/hotels/doctype/hotel_room/hotel_room.py +++ b/erpnext/hotels/doctype/hotel_room/hotel_room.py @@ -1,8 +1,6 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2017, Frappe Technologies Pvt. Ltd. and contributors # For license information, please see license.txt -from __future__ import unicode_literals import frappe from frappe.model.document import Document diff --git a/erpnext/hotels/doctype/hotel_room/test_hotel_room.py b/erpnext/hotels/doctype/hotel_room/test_hotel_room.py index 4fedbd42a92..95efe2c6068 100644 --- a/erpnext/hotels/doctype/hotel_room/test_hotel_room.py +++ b/erpnext/hotels/doctype/hotel_room/test_hotel_room.py @@ -1,7 +1,5 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2017, Frappe Technologies Pvt. Ltd. and Contributors # See license.txt -from __future__ import unicode_literals import unittest diff --git a/erpnext/hotels/doctype/hotel_room_amenity/hotel_room_amenity.py b/erpnext/hotels/doctype/hotel_room_amenity/hotel_room_amenity.py index 982b3ef911d..166493124a7 100644 --- a/erpnext/hotels/doctype/hotel_room_amenity/hotel_room_amenity.py +++ b/erpnext/hotels/doctype/hotel_room_amenity/hotel_room_amenity.py @@ -1,8 +1,6 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2017, Frappe Technologies Pvt. Ltd. and contributors # For license information, please see license.txt -from __future__ import unicode_literals from frappe.model.document import Document diff --git a/erpnext/hotels/doctype/hotel_room_package/hotel_room_package.py b/erpnext/hotels/doctype/hotel_room_package/hotel_room_package.py index 1864081842d..aedc83a8468 100644 --- a/erpnext/hotels/doctype/hotel_room_package/hotel_room_package.py +++ b/erpnext/hotels/doctype/hotel_room_package/hotel_room_package.py @@ -1,8 +1,6 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2017, Frappe Technologies Pvt. Ltd. and contributors # For license information, please see license.txt -from __future__ import unicode_literals import frappe from frappe.model.document import Document diff --git a/erpnext/hotels/doctype/hotel_room_package/test_hotel_room_package.py b/erpnext/hotels/doctype/hotel_room_package/test_hotel_room_package.py index fe5d79dcc32..749731f4918 100644 --- a/erpnext/hotels/doctype/hotel_room_package/test_hotel_room_package.py +++ b/erpnext/hotels/doctype/hotel_room_package/test_hotel_room_package.py @@ -1,7 +1,5 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2017, Frappe Technologies Pvt. Ltd. and Contributors # See license.txt -from __future__ import unicode_literals import unittest diff --git a/erpnext/hotels/doctype/hotel_room_pricing/hotel_room_pricing.py b/erpnext/hotels/doctype/hotel_room_pricing/hotel_room_pricing.py index 5797fef30db..d28e5734264 100644 --- a/erpnext/hotels/doctype/hotel_room_pricing/hotel_room_pricing.py +++ b/erpnext/hotels/doctype/hotel_room_pricing/hotel_room_pricing.py @@ -1,8 +1,6 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2017, Frappe Technologies Pvt. Ltd. and contributors # For license information, please see license.txt -from __future__ import unicode_literals from frappe.model.document import Document diff --git a/erpnext/hotels/doctype/hotel_room_pricing/test_hotel_room_pricing.py b/erpnext/hotels/doctype/hotel_room_pricing/test_hotel_room_pricing.py index 72030c69397..34550096dd9 100644 --- a/erpnext/hotels/doctype/hotel_room_pricing/test_hotel_room_pricing.py +++ b/erpnext/hotels/doctype/hotel_room_pricing/test_hotel_room_pricing.py @@ -1,7 +1,5 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2017, Frappe Technologies Pvt. Ltd. and Contributors # See license.txt -from __future__ import unicode_literals import unittest diff --git a/erpnext/hotels/doctype/hotel_room_pricing_item/hotel_room_pricing_item.py b/erpnext/hotels/doctype/hotel_room_pricing_item/hotel_room_pricing_item.py index 4a344df8485..2e6bb5fac29 100644 --- a/erpnext/hotels/doctype/hotel_room_pricing_item/hotel_room_pricing_item.py +++ b/erpnext/hotels/doctype/hotel_room_pricing_item/hotel_room_pricing_item.py @@ -1,8 +1,6 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2017, Frappe Technologies Pvt. Ltd. and contributors # For license information, please see license.txt -from __future__ import unicode_literals from frappe.model.document import Document diff --git a/erpnext/hotels/doctype/hotel_room_pricing_package/hotel_room_pricing_package.py b/erpnext/hotels/doctype/hotel_room_pricing_package/hotel_room_pricing_package.py index f594ac709ec..ebbdb6ec6c5 100644 --- a/erpnext/hotels/doctype/hotel_room_pricing_package/hotel_room_pricing_package.py +++ b/erpnext/hotels/doctype/hotel_room_pricing_package/hotel_room_pricing_package.py @@ -1,8 +1,6 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2017, Frappe Technologies Pvt. Ltd. and contributors # For license information, please see license.txt -from __future__ import unicode_literals from frappe.model.document import Document diff --git a/erpnext/hotels/doctype/hotel_room_pricing_package/test_hotel_room_pricing_package.py b/erpnext/hotels/doctype/hotel_room_pricing_package/test_hotel_room_pricing_package.py index ea258ccb75d..196e6504b51 100644 --- a/erpnext/hotels/doctype/hotel_room_pricing_package/test_hotel_room_pricing_package.py +++ b/erpnext/hotels/doctype/hotel_room_pricing_package/test_hotel_room_pricing_package.py @@ -1,7 +1,5 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2017, Frappe Technologies Pvt. Ltd. and Contributors # See license.txt -from __future__ import unicode_literals import unittest diff --git a/erpnext/hotels/doctype/hotel_room_reservation/hotel_room_reservation.py b/erpnext/hotels/doctype/hotel_room_reservation/hotel_room_reservation.py index 4944862284a..7725955396b 100644 --- a/erpnext/hotels/doctype/hotel_room_reservation/hotel_room_reservation.py +++ b/erpnext/hotels/doctype/hotel_room_reservation/hotel_room_reservation.py @@ -1,8 +1,6 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2017, Frappe Technologies Pvt. Ltd. and contributors # For license information, please see license.txt -from __future__ import unicode_literals import json diff --git a/erpnext/hotels/doctype/hotel_room_reservation/test_hotel_room_reservation.py b/erpnext/hotels/doctype/hotel_room_reservation/test_hotel_room_reservation.py index e03005cf042..bb32a27fa7c 100644 --- a/erpnext/hotels/doctype/hotel_room_reservation/test_hotel_room_reservation.py +++ b/erpnext/hotels/doctype/hotel_room_reservation/test_hotel_room_reservation.py @@ -1,7 +1,5 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2017, Frappe Technologies Pvt. Ltd. and Contributors # See license.txt -from __future__ import unicode_literals import unittest diff --git a/erpnext/hotels/doctype/hotel_room_reservation_item/hotel_room_reservation_item.py b/erpnext/hotels/doctype/hotel_room_reservation_item/hotel_room_reservation_item.py index 0cf854722e1..41d86ddca65 100644 --- a/erpnext/hotels/doctype/hotel_room_reservation_item/hotel_room_reservation_item.py +++ b/erpnext/hotels/doctype/hotel_room_reservation_item/hotel_room_reservation_item.py @@ -1,8 +1,6 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2017, Frappe Technologies Pvt. Ltd. and contributors # For license information, please see license.txt -from __future__ import unicode_literals from frappe.model.document import Document diff --git a/erpnext/hotels/doctype/hotel_room_type/hotel_room_type.py b/erpnext/hotels/doctype/hotel_room_type/hotel_room_type.py index 610cf181c1d..7ab529fee96 100644 --- a/erpnext/hotels/doctype/hotel_room_type/hotel_room_type.py +++ b/erpnext/hotels/doctype/hotel_room_type/hotel_room_type.py @@ -1,8 +1,6 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2017, Frappe Technologies Pvt. Ltd. and contributors # For license information, please see license.txt -from __future__ import unicode_literals from frappe.model.document import Document diff --git a/erpnext/hotels/doctype/hotel_room_type/test_hotel_room_type.py b/erpnext/hotels/doctype/hotel_room_type/test_hotel_room_type.py index 6dba7b7407b..8d1147d0f20 100644 --- a/erpnext/hotels/doctype/hotel_room_type/test_hotel_room_type.py +++ b/erpnext/hotels/doctype/hotel_room_type/test_hotel_room_type.py @@ -1,7 +1,5 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2017, Frappe Technologies Pvt. Ltd. and Contributors # See license.txt -from __future__ import unicode_literals import unittest diff --git a/erpnext/hotels/doctype/hotel_settings/hotel_settings.py b/erpnext/hotels/doctype/hotel_settings/hotel_settings.py index f8f8fe964da..8376d509693 100644 --- a/erpnext/hotels/doctype/hotel_settings/hotel_settings.py +++ b/erpnext/hotels/doctype/hotel_settings/hotel_settings.py @@ -1,8 +1,6 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2017, Frappe Technologies Pvt. Ltd. and contributors # For license information, please see license.txt -from __future__ import unicode_literals from frappe.model.document import Document diff --git a/erpnext/hotels/doctype/hotel_settings/test_hotel_settings.py b/erpnext/hotels/doctype/hotel_settings/test_hotel_settings.py index 5cf58b994e1..e76c00ce101 100644 --- a/erpnext/hotels/doctype/hotel_settings/test_hotel_settings.py +++ b/erpnext/hotels/doctype/hotel_settings/test_hotel_settings.py @@ -1,7 +1,5 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2017, Frappe Technologies Pvt. Ltd. and Contributors # See license.txt -from __future__ import unicode_literals import unittest diff --git a/erpnext/hotels/report/hotel_room_occupancy/hotel_room_occupancy.py b/erpnext/hotels/report/hotel_room_occupancy/hotel_room_occupancy.py index f02baebdf6f..c43589d2a8d 100644 --- a/erpnext/hotels/report/hotel_room_occupancy/hotel_room_occupancy.py +++ b/erpnext/hotels/report/hotel_room_occupancy/hotel_room_occupancy.py @@ -1,7 +1,6 @@ # Copyright (c) 2013, Frappe Technologies Pvt. Ltd. and contributors # For license information, please see license.txt -from __future__ import unicode_literals import frappe from frappe import _ diff --git a/erpnext/hr/doctype/__init__.py b/erpnext/hr/doctype/__init__.py index baffc488252..e69de29bb2d 100644 --- a/erpnext/hr/doctype/__init__.py +++ b/erpnext/hr/doctype/__init__.py @@ -1 +0,0 @@ -from __future__ import unicode_literals diff --git a/erpnext/hr/doctype/appointment_letter/appointment_letter.py b/erpnext/hr/doctype/appointment_letter/appointment_letter.py index b9a8ec63017..0120188d31c 100644 --- a/erpnext/hr/doctype/appointment_letter/appointment_letter.py +++ b/erpnext/hr/doctype/appointment_letter/appointment_letter.py @@ -1,8 +1,6 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2019, Frappe Technologies Pvt. Ltd. and contributors # For license information, please see license.txt -from __future__ import unicode_literals import frappe from frappe.model.document import Document diff --git a/erpnext/hr/doctype/appointment_letter/test_appointment_letter.py b/erpnext/hr/doctype/appointment_letter/test_appointment_letter.py index 88637b9fe93..e0f65b45d48 100644 --- a/erpnext/hr/doctype/appointment_letter/test_appointment_letter.py +++ b/erpnext/hr/doctype/appointment_letter/test_appointment_letter.py @@ -1,7 +1,5 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2019, Frappe Technologies Pvt. Ltd. and Contributors # See license.txt -from __future__ import unicode_literals # import frappe import unittest diff --git a/erpnext/hr/doctype/appointment_letter_content/appointment_letter_content.py b/erpnext/hr/doctype/appointment_letter_content/appointment_letter_content.py index f4db456af38..d158013d746 100644 --- a/erpnext/hr/doctype/appointment_letter_content/appointment_letter_content.py +++ b/erpnext/hr/doctype/appointment_letter_content/appointment_letter_content.py @@ -1,8 +1,6 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2019, Frappe Technologies Pvt. Ltd. and contributors # For license information, please see license.txt -from __future__ import unicode_literals # import frappe from frappe.model.document import Document diff --git a/erpnext/hr/doctype/appointment_letter_template/appointment_letter_template.py b/erpnext/hr/doctype/appointment_letter_template/appointment_letter_template.py index acb5c1f6924..9ac726e06d3 100644 --- a/erpnext/hr/doctype/appointment_letter_template/appointment_letter_template.py +++ b/erpnext/hr/doctype/appointment_letter_template/appointment_letter_template.py @@ -1,8 +1,6 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2019, Frappe Technologies Pvt. Ltd. and contributors # For license information, please see license.txt -from __future__ import unicode_literals # import frappe from frappe.model.document import Document diff --git a/erpnext/hr/doctype/appointment_letter_template/test_appointment_letter_template.py b/erpnext/hr/doctype/appointment_letter_template/test_appointment_letter_template.py index 46dd3e12727..aa87da323fc 100644 --- a/erpnext/hr/doctype/appointment_letter_template/test_appointment_letter_template.py +++ b/erpnext/hr/doctype/appointment_letter_template/test_appointment_letter_template.py @@ -1,7 +1,5 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2019, Frappe Technologies Pvt. Ltd. and Contributors # See license.txt -from __future__ import unicode_literals # import frappe import unittest diff --git a/erpnext/hr/doctype/appraisal/__init__.py b/erpnext/hr/doctype/appraisal/__init__.py index baffc488252..e69de29bb2d 100644 --- a/erpnext/hr/doctype/appraisal/__init__.py +++ b/erpnext/hr/doctype/appraisal/__init__.py @@ -1 +0,0 @@ -from __future__ import unicode_literals diff --git a/erpnext/hr/doctype/appraisal/appraisal.py b/erpnext/hr/doctype/appraisal/appraisal.py index 96a4ffa524a..83273f86544 100644 --- a/erpnext/hr/doctype/appraisal/appraisal.py +++ b/erpnext/hr/doctype/appraisal/appraisal.py @@ -1,7 +1,6 @@ # Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors # License: GNU General Public License v3. See license.txt -from __future__ import unicode_literals import frappe from frappe import _ diff --git a/erpnext/hr/doctype/appraisal/test_appraisal.py b/erpnext/hr/doctype/appraisal/test_appraisal.py index cf2bd7c2427..90c30ef3475 100644 --- a/erpnext/hr/doctype/appraisal/test_appraisal.py +++ b/erpnext/hr/doctype/appraisal/test_appraisal.py @@ -1,6 +1,5 @@ # Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors and Contributors # See license.txt -from __future__ import unicode_literals import unittest diff --git a/erpnext/hr/doctype/appraisal_goal/__init__.py b/erpnext/hr/doctype/appraisal_goal/__init__.py index baffc488252..e69de29bb2d 100644 --- a/erpnext/hr/doctype/appraisal_goal/__init__.py +++ b/erpnext/hr/doctype/appraisal_goal/__init__.py @@ -1 +0,0 @@ -from __future__ import unicode_literals diff --git a/erpnext/hr/doctype/appraisal_goal/appraisal_goal.py b/erpnext/hr/doctype/appraisal_goal/appraisal_goal.py index d9789a028bd..3cbc9188eee 100644 --- a/erpnext/hr/doctype/appraisal_goal/appraisal_goal.py +++ b/erpnext/hr/doctype/appraisal_goal/appraisal_goal.py @@ -1,7 +1,6 @@ # Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors # License: GNU General Public License v3. See license.txt -from __future__ import unicode_literals from frappe.model.document import Document diff --git a/erpnext/hr/doctype/appraisal_template/__init__.py b/erpnext/hr/doctype/appraisal_template/__init__.py index baffc488252..e69de29bb2d 100644 --- a/erpnext/hr/doctype/appraisal_template/__init__.py +++ b/erpnext/hr/doctype/appraisal_template/__init__.py @@ -1 +0,0 @@ -from __future__ import unicode_literals diff --git a/erpnext/hr/doctype/appraisal_template/appraisal_template.py b/erpnext/hr/doctype/appraisal_template/appraisal_template.py index d10a0de3bce..6b5921e6a6e 100644 --- a/erpnext/hr/doctype/appraisal_template/appraisal_template.py +++ b/erpnext/hr/doctype/appraisal_template/appraisal_template.py @@ -1,7 +1,6 @@ # Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors # License: GNU General Public License v3. See license.txt -from __future__ import unicode_literals import frappe from frappe import _ diff --git a/erpnext/hr/doctype/appraisal_template/appraisal_template_dashboard.py b/erpnext/hr/doctype/appraisal_template/appraisal_template_dashboard.py index b8d04944edb..116a3f9118a 100644 --- a/erpnext/hr/doctype/appraisal_template/appraisal_template_dashboard.py +++ b/erpnext/hr/doctype/appraisal_template/appraisal_template_dashboard.py @@ -1,6 +1,3 @@ -from __future__ import unicode_literals - - def get_data(): return { 'fieldname': 'kra_template', diff --git a/erpnext/hr/doctype/appraisal_template/test_appraisal_template.py b/erpnext/hr/doctype/appraisal_template/test_appraisal_template.py index a814ec8d5b2..d0e81a7dc5b 100644 --- a/erpnext/hr/doctype/appraisal_template/test_appraisal_template.py +++ b/erpnext/hr/doctype/appraisal_template/test_appraisal_template.py @@ -1,6 +1,5 @@ # Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors and Contributors # See license.txt -from __future__ import unicode_literals import unittest diff --git a/erpnext/hr/doctype/appraisal_template_goal/__init__.py b/erpnext/hr/doctype/appraisal_template_goal/__init__.py index baffc488252..e69de29bb2d 100644 --- a/erpnext/hr/doctype/appraisal_template_goal/__init__.py +++ b/erpnext/hr/doctype/appraisal_template_goal/__init__.py @@ -1 +0,0 @@ -from __future__ import unicode_literals diff --git a/erpnext/hr/doctype/appraisal_template_goal/appraisal_template_goal.py b/erpnext/hr/doctype/appraisal_template_goal/appraisal_template_goal.py index 1b15fbd51e1..e6c5f64e08e 100644 --- a/erpnext/hr/doctype/appraisal_template_goal/appraisal_template_goal.py +++ b/erpnext/hr/doctype/appraisal_template_goal/appraisal_template_goal.py @@ -1,7 +1,6 @@ # Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors # License: GNU General Public License v3. See license.txt -from __future__ import unicode_literals from frappe.model.document import Document diff --git a/erpnext/hr/doctype/attendance/__init__.py b/erpnext/hr/doctype/attendance/__init__.py index baffc488252..e69de29bb2d 100644 --- a/erpnext/hr/doctype/attendance/__init__.py +++ b/erpnext/hr/doctype/attendance/__init__.py @@ -1 +0,0 @@ -from __future__ import unicode_literals diff --git a/erpnext/hr/doctype/attendance/attendance.py b/erpnext/hr/doctype/attendance/attendance.py index 002f9bbcac2..7dcfac249f4 100644 --- a/erpnext/hr/doctype/attendance/attendance.py +++ b/erpnext/hr/doctype/attendance/attendance.py @@ -1,7 +1,6 @@ # Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors # License: GNU General Public License v3. See license.txt -from __future__ import unicode_literals import frappe from frappe import _ diff --git a/erpnext/hr/doctype/attendance/attendance_dashboard.py b/erpnext/hr/doctype/attendance/attendance_dashboard.py index bbe67dfcc8f..4bb36a0d7fd 100644 --- a/erpnext/hr/doctype/attendance/attendance_dashboard.py +++ b/erpnext/hr/doctype/attendance/attendance_dashboard.py @@ -1,6 +1,3 @@ -from __future__ import unicode_literals - - def get_data(): return { 'fieldname': 'attendance', diff --git a/erpnext/hr/doctype/attendance/attendance_list.js b/erpnext/hr/doctype/attendance/attendance_list.js index 9a3bac0eb23..6b3c29a76b4 100644 --- a/erpnext/hr/doctype/attendance/attendance_list.js +++ b/erpnext/hr/doctype/attendance/attendance_list.js @@ -9,83 +9,86 @@ frappe.listview_settings['Attendance'] = { return [__(doc.status), "orange", "status,=," + doc.status]; } }, + onload: function(list_view) { let me = this; - const months = moment.months() - list_view.page.add_inner_button( __("Mark Attendance"), function() { + const months = moment.months(); + list_view.page.add_inner_button(__("Mark Attendance"), function() { let dialog = new frappe.ui.Dialog({ title: __("Mark Attendance"), - fields: [ - { - fieldname: 'employee', - label: __('For Employee'), - fieldtype: 'Link', - options: 'Employee', - get_query: () => { - return {query: "erpnext.controllers.queries.employee_query"} - }, - reqd: 1, - onchange: function() { - dialog.set_df_property("unmarked_days", "hidden", 1); - dialog.set_df_property("status", "hidden", 1); - dialog.set_df_property("month", "value", ''); + fields: [{ + fieldname: 'employee', + label: __('For Employee'), + fieldtype: 'Link', + options: 'Employee', + get_query: () => { + return {query: "erpnext.controllers.queries.employee_query"}; + }, + reqd: 1, + onchange: function() { + dialog.set_df_property("unmarked_days", "hidden", 1); + dialog.set_df_property("status", "hidden", 1); + dialog.set_df_property("month", "value", ''); + dialog.set_df_property("unmarked_days", "options", []); + dialog.no_unmarked_days_left = false; + } + }, + { + label: __("For Month"), + fieldtype: "Select", + fieldname: "month", + options: months, + reqd: 1, + onchange: function() { + if (dialog.fields_dict.employee.value && dialog.fields_dict.month.value) { + dialog.set_df_property("status", "hidden", 0); dialog.set_df_property("unmarked_days", "options", []); dialog.no_unmarked_days_left = false; + me.get_multi_select_options(dialog.fields_dict.employee.value, dialog.fields_dict.month.value).then(options => { + if (options.length > 0) { + dialog.set_df_property("unmarked_days", "hidden", 0); + dialog.set_df_property("unmarked_days", "options", options); + } else { + dialog.no_unmarked_days_left = true; + } + }); } - }, - { - label: __("For Month"), - fieldtype: "Select", - fieldname: "month", - options: months, - reqd: 1, - onchange: function() { - if(dialog.fields_dict.employee.value && dialog.fields_dict.month.value) { - dialog.set_df_property("status", "hidden", 0); - dialog.set_df_property("unmarked_days", "options", []); - dialog.no_unmarked_days_left = false; - me.get_multi_select_options(dialog.fields_dict.employee.value, dialog.fields_dict.month.value).then(options =>{ - if (options.length > 0) { - dialog.set_df_property("unmarked_days", "hidden", 0); - dialog.set_df_property("unmarked_days", "options", options); - } else { - dialog.no_unmarked_days_left = true; - } - }); - } - } - }, - { - label: __("Status"), - fieldtype: "Select", - fieldname: "status", - options: ["Present", "Absent", "Half Day", "Work From Home"], - hidden:1, - reqd: 1, + } + }, + { + label: __("Status"), + fieldtype: "Select", + fieldname: "status", + options: ["Present", "Absent", "Half Day", "Work From Home"], + hidden: 1, + reqd: 1, - }, - { - label: __("Unmarked Attendance for days"), - fieldname: "unmarked_days", - fieldtype: "MultiCheck", - options: [], - columns: 2, - hidden: 1 - }, - ], - primary_action(data) { + }, + { + label: __("Unmarked Attendance for days"), + fieldname: "unmarked_days", + fieldtype: "MultiCheck", + options: [], + columns: 2, + hidden: 1 + }], + primary_action(data) { if (cur_dialog.no_unmarked_days_left) { - frappe.msgprint(__("Attendance for the month of {0} , has already been marked for the Employee {1}",[dialog.fields_dict.month.value, dialog.fields_dict.employee.value])); + frappe.msgprint(__("Attendance for the month of {0} , has already been marked for the Employee {1}", + [dialog.fields_dict.month.value, dialog.fields_dict.employee.value])); } else { - frappe.confirm(__('Mark attendance as {0} for {1} on selected dates?', [data.status,data.month]), () => { + frappe.confirm(__('Mark attendance as {0} for {1} on selected dates?', [data.status, data.month]), () => { frappe.call({ method: "erpnext.hr.doctype.attendance.attendance.mark_bulk_attendance", args: { data: data }, - callback: function(r) { + callback: function (r) { if (r.message === 1) { - frappe.show_alert({message: __("Attendance Marked"), indicator: 'blue'}); + frappe.show_alert({ + message: __("Attendance Marked"), + indicator: 'blue' + }); cur_dialog.hide(); } } @@ -101,21 +104,26 @@ frappe.listview_settings['Attendance'] = { dialog.show(); }); }, - get_multi_select_options: function(employee, month){ + + get_multi_select_options: function(employee, month) { return new Promise(resolve => { frappe.call({ method: 'erpnext.hr.doctype.attendance.attendance.get_unmarked_days', async: false, - args:{ + args: { employee: employee, month: month, } }).then(r => { var options = []; - for(var d in r.message){ + for (var d in r.message) { var momentObj = moment(r.message[d], 'YYYY-MM-DD'); var date = momentObj.format('DD-MM-YYYY'); - options.push({ "label":date, "value": r.message[d] , "checked": 1}); + options.push({ + "label": date, + "value": r.message[d], + "checked": 1 + }); } resolve(options); }); diff --git a/erpnext/hr/doctype/attendance/test_attendance.py b/erpnext/hr/doctype/attendance/test_attendance.py index ab443774212..a770d70ffa9 100644 --- a/erpnext/hr/doctype/attendance/test_attendance.py +++ b/erpnext/hr/doctype/attendance/test_attendance.py @@ -1,6 +1,5 @@ # Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors and Contributors # See license.txt -from __future__ import unicode_literals import unittest diff --git a/erpnext/hr/doctype/attendance_request/attendance_request.py b/erpnext/hr/doctype/attendance_request/attendance_request.py index 1e7429656d2..8fbe7c7a9ad 100644 --- a/erpnext/hr/doctype/attendance_request/attendance_request.py +++ b/erpnext/hr/doctype/attendance_request/attendance_request.py @@ -1,8 +1,6 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2018, Frappe Technologies Pvt. Ltd. and contributors # For license information, please see license.txt -from __future__ import unicode_literals import frappe from frappe import _ diff --git a/erpnext/hr/doctype/attendance_request/attendance_request_dashboard.py b/erpnext/hr/doctype/attendance_request/attendance_request_dashboard.py index 8feb6f2f23e..91970575a13 100644 --- a/erpnext/hr/doctype/attendance_request/attendance_request_dashboard.py +++ b/erpnext/hr/doctype/attendance_request/attendance_request_dashboard.py @@ -1,6 +1,3 @@ -from __future__ import unicode_literals - - def get_data(): return { 'fieldname': 'attendance_request', diff --git a/erpnext/hr/doctype/attendance_request/test_attendance_request.py b/erpnext/hr/doctype/attendance_request/test_attendance_request.py index a9db74cbf75..3f0442c7d69 100644 --- a/erpnext/hr/doctype/attendance_request/test_attendance_request.py +++ b/erpnext/hr/doctype/attendance_request/test_attendance_request.py @@ -1,7 +1,5 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2018, Frappe Technologies Pvt. Ltd. and Contributors # See license.txt -from __future__ import unicode_literals import unittest from datetime import date diff --git a/erpnext/hr/doctype/branch/__init__.py b/erpnext/hr/doctype/branch/__init__.py index baffc488252..e69de29bb2d 100644 --- a/erpnext/hr/doctype/branch/__init__.py +++ b/erpnext/hr/doctype/branch/__init__.py @@ -1 +0,0 @@ -from __future__ import unicode_literals diff --git a/erpnext/hr/doctype/branch/branch.py b/erpnext/hr/doctype/branch/branch.py index c770dc34090..133ada05bf0 100644 --- a/erpnext/hr/doctype/branch/branch.py +++ b/erpnext/hr/doctype/branch/branch.py @@ -1,7 +1,6 @@ # Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors # License: GNU General Public License v3. See license.txt -from __future__ import unicode_literals from frappe.model.document import Document diff --git a/erpnext/hr/doctype/branch/test_branch.py b/erpnext/hr/doctype/branch/test_branch.py index 7bf9b395308..e84c6e4c60e 100644 --- a/erpnext/hr/doctype/branch/test_branch.py +++ b/erpnext/hr/doctype/branch/test_branch.py @@ -1,6 +1,5 @@ # Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors # License: GNU General Public License v3. See license.txt -from __future__ import unicode_literals import frappe diff --git a/erpnext/hr/doctype/compensatory_leave_request/compensatory_leave_request.py b/erpnext/hr/doctype/compensatory_leave_request/compensatory_leave_request.py index f24483bf827..7d6051508ad 100644 --- a/erpnext/hr/doctype/compensatory_leave_request/compensatory_leave_request.py +++ b/erpnext/hr/doctype/compensatory_leave_request/compensatory_leave_request.py @@ -1,8 +1,6 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2018, Frappe Technologies Pvt. Ltd. and contributors # For license information, please see license.txt -from __future__ import unicode_literals import frappe from frappe import _ diff --git a/erpnext/hr/doctype/compensatory_leave_request/test_compensatory_leave_request.py b/erpnext/hr/doctype/compensatory_leave_request/test_compensatory_leave_request.py index 95bdd514ef3..5e51879328b 100644 --- a/erpnext/hr/doctype/compensatory_leave_request/test_compensatory_leave_request.py +++ b/erpnext/hr/doctype/compensatory_leave_request/test_compensatory_leave_request.py @@ -1,7 +1,5 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2018, Frappe Technologies Pvt. Ltd. and Contributors # See license.txt -from __future__ import unicode_literals import unittest diff --git a/erpnext/hr/doctype/daily_work_summary/daily_work_summary.py b/erpnext/hr/doctype/daily_work_summary/daily_work_summary.py index 92cf6aac851..fe11c47e60c 100644 --- a/erpnext/hr/doctype/daily_work_summary/daily_work_summary.py +++ b/erpnext/hr/doctype/daily_work_summary/daily_work_summary.py @@ -1,15 +1,12 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and contributors # For license information, please see license.txt -from __future__ import unicode_literals import frappe from email_reply_parser import EmailReplyParser from frappe import _ from frappe.model.document import Document from frappe.utils import global_date_format -from six import string_types class DailyWorkSummary(Document): @@ -109,7 +106,7 @@ def get_user_emails_from_group(group): :param group: Daily Work Summary Group `name`''' group_doc = group - if isinstance(group_doc, string_types): + if isinstance(group_doc, str): group_doc = frappe.get_doc('Daily Work Summary Group', group) emails = get_users_email(group_doc) diff --git a/erpnext/hr/doctype/daily_work_summary/test_daily_work_summary.py b/erpnext/hr/doctype/daily_work_summary/test_daily_work_summary.py index bed12e31eaa..5edfb315564 100644 --- a/erpnext/hr/doctype/daily_work_summary/test_daily_work_summary.py +++ b/erpnext/hr/doctype/daily_work_summary/test_daily_work_summary.py @@ -1,7 +1,5 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors # See license.txt -from __future__ import unicode_literals import os import unittest @@ -74,7 +72,6 @@ class TestDailyWorkSummary(unittest.TestCase): from `tabEmail Queue` as q, `tabEmail Queue Recipient` as r \ where q.name = r.parent""", as_dict=1) - frappe.db.commit() def setup_groups(self, hour=None): # setup email to trigger at this hour diff --git a/erpnext/hr/doctype/daily_work_summary_group/daily_work_summary_group.py b/erpnext/hr/doctype/daily_work_summary_group/daily_work_summary_group.py index 152b1a9c7c5..ed98168aef7 100644 --- a/erpnext/hr/doctype/daily_work_summary_group/daily_work_summary_group.py +++ b/erpnext/hr/doctype/daily_work_summary_group/daily_work_summary_group.py @@ -1,8 +1,6 @@ -# # -*- coding: utf-8 -*- # # Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and contributors # # For license information, please see license.txt -from __future__ import unicode_literals import frappe import frappe.utils diff --git a/erpnext/hr/doctype/daily_work_summary_group_user/daily_work_summary_group_user.py b/erpnext/hr/doctype/daily_work_summary_group_user/daily_work_summary_group_user.py index d69a7fbf987..6e0809af332 100644 --- a/erpnext/hr/doctype/daily_work_summary_group_user/daily_work_summary_group_user.py +++ b/erpnext/hr/doctype/daily_work_summary_group_user/daily_work_summary_group_user.py @@ -1,8 +1,6 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2018, Frappe Technologies Pvt. Ltd. and contributors # For license information, please see license.txt -from __future__ import unicode_literals from frappe.model.document import Document diff --git a/erpnext/hr/doctype/department/__init__.py b/erpnext/hr/doctype/department/__init__.py index baffc488252..e69de29bb2d 100644 --- a/erpnext/hr/doctype/department/__init__.py +++ b/erpnext/hr/doctype/department/__init__.py @@ -1 +0,0 @@ -from __future__ import unicode_literals diff --git a/erpnext/hr/doctype/department/department.py b/erpnext/hr/doctype/department/department.py index b4771b3fed0..ed0bfcf0d5a 100644 --- a/erpnext/hr/doctype/department/department.py +++ b/erpnext/hr/doctype/department/department.py @@ -1,7 +1,6 @@ # Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors # License: GNU General Public License v3. See license.txt -from __future__ import unicode_literals import frappe from frappe.utils.nestedset import NestedSet, get_root_of diff --git a/erpnext/hr/doctype/department/test_department.py b/erpnext/hr/doctype/department/test_department.py index 2fb3b95ef43..95bf6635011 100644 --- a/erpnext/hr/doctype/department/test_department.py +++ b/erpnext/hr/doctype/department/test_department.py @@ -1,6 +1,5 @@ # Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors # License: GNU General Public License v3. See license.txt -from __future__ import unicode_literals import unittest diff --git a/erpnext/hr/doctype/department_approver/department_approver.py b/erpnext/hr/doctype/department_approver/department_approver.py index 113ea1887fc..375ae7c70ae 100644 --- a/erpnext/hr/doctype/department_approver/department_approver.py +++ b/erpnext/hr/doctype/department_approver/department_approver.py @@ -1,8 +1,6 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2018, Frappe Technologies Pvt. Ltd. and contributors # For license information, please see license.txt -from __future__ import unicode_literals import frappe from frappe import _ diff --git a/erpnext/hr/doctype/designation/__init__.py b/erpnext/hr/doctype/designation/__init__.py index baffc488252..e69de29bb2d 100644 --- a/erpnext/hr/doctype/designation/__init__.py +++ b/erpnext/hr/doctype/designation/__init__.py @@ -1 +0,0 @@ -from __future__ import unicode_literals diff --git a/erpnext/hr/doctype/designation/designation.py b/erpnext/hr/doctype/designation/designation.py index 0291a992cd9..d7be55cad69 100644 --- a/erpnext/hr/doctype/designation/designation.py +++ b/erpnext/hr/doctype/designation/designation.py @@ -1,7 +1,6 @@ # Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors # License: GNU General Public License v3. See license.txt -from __future__ import unicode_literals from frappe.model.document import Document diff --git a/erpnext/hr/doctype/designation/test_designation.py b/erpnext/hr/doctype/designation/test_designation.py index 33aa2433cee..f2d6d36ff88 100644 --- a/erpnext/hr/doctype/designation/test_designation.py +++ b/erpnext/hr/doctype/designation/test_designation.py @@ -1,6 +1,5 @@ # Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors # License: GNU General Public License v3. See license.txt -from __future__ import unicode_literals import frappe diff --git a/erpnext/hr/doctype/designation_skill/designation_skill.py b/erpnext/hr/doctype/designation_skill/designation_skill.py index 2074dc9df51..c35223b3c10 100644 --- a/erpnext/hr/doctype/designation_skill/designation_skill.py +++ b/erpnext/hr/doctype/designation_skill/designation_skill.py @@ -1,8 +1,6 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2019, Frappe Technologies Pvt. Ltd. and contributors # For license information, please see license.txt -from __future__ import unicode_literals # import frappe from frappe.model.document import Document diff --git a/erpnext/hr/doctype/driver/driver.py b/erpnext/hr/doctype/driver/driver.py index 5c428b57fc9..26981890ed6 100644 --- a/erpnext/hr/doctype/driver/driver.py +++ b/erpnext/hr/doctype/driver/driver.py @@ -1,8 +1,6 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2017, Frappe Technologies Pvt. Ltd. and contributors # For license information, please see license.txt -from __future__ import unicode_literals from frappe.model.document import Document diff --git a/erpnext/hr/doctype/driver/test_driver.py b/erpnext/hr/doctype/driver/test_driver.py index fa3623745ba..22707293a05 100644 --- a/erpnext/hr/doctype/driver/test_driver.py +++ b/erpnext/hr/doctype/driver/test_driver.py @@ -1,7 +1,5 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2017, Frappe Technologies Pvt. Ltd. and Contributors # See license.txt -from __future__ import unicode_literals import unittest diff --git a/erpnext/hr/doctype/driving_license_category/driving_license_category.py b/erpnext/hr/doctype/driving_license_category/driving_license_category.py index 63ac4184bd9..a1a6d55cb4c 100644 --- a/erpnext/hr/doctype/driving_license_category/driving_license_category.py +++ b/erpnext/hr/doctype/driving_license_category/driving_license_category.py @@ -1,8 +1,6 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2017, Frappe Technologies Pvt. Ltd. and contributors # For license information, please see license.txt -from __future__ import unicode_literals from frappe.model.document import Document diff --git a/erpnext/hr/doctype/employee/__init__.py b/erpnext/hr/doctype/employee/__init__.py index baffc488252..e69de29bb2d 100644 --- a/erpnext/hr/doctype/employee/__init__.py +++ b/erpnext/hr/doctype/employee/__init__.py @@ -1 +0,0 @@ -from __future__ import unicode_literals diff --git a/erpnext/hr/doctype/employee/employee.js b/erpnext/hr/doctype/employee/employee.js index 5639cc9ea46..13b33e2e74c 100755 --- a/erpnext/hr/doctype/employee/employee.js +++ b/erpnext/hr/doctype/employee/employee.js @@ -15,19 +15,20 @@ erpnext.hr.EmployeeController = class EmployeeController extends frappe.ui.form. } refresh() { - var me = this; erpnext.toggle_naming_series(); } date_of_birth() { return cur_frm.call({ method: "get_retirement_date", - args: {date_of_birth: this.frm.doc.date_of_birth} + args: { + date_of_birth: this.frm.doc.date_of_birth + } }); } salutation() { - if(this.frm.doc.salutation) { + if (this.frm.doc.salutation) { this.frm.set_value("gender", { "Mr": "Male", "Ms": "Female" @@ -36,8 +37,9 @@ erpnext.hr.EmployeeController = class EmployeeController extends frappe.ui.form. } }; -frappe.ui.form.on('Employee',{ - setup: function(frm) { + +frappe.ui.form.on('Employee', { + setup: function (frm) { frm.set_query("leave_policy", function() { return { "filters": { @@ -46,7 +48,7 @@ frappe.ui.form.on('Employee',{ }; }); }, - onload:function(frm) { + onload: function (frm) { frm.set_query("department", function() { return { "filters": { @@ -55,23 +57,28 @@ frappe.ui.form.on('Employee',{ }; }); }, - prefered_contact_email:function(frm){ - frm.events.update_contact(frm) + prefered_contact_email: function(frm) { + frm.events.update_contact(frm); }, - personal_email:function(frm){ - frm.events.update_contact(frm) + + personal_email: function(frm) { + frm.events.update_contact(frm); }, - company_email:function(frm){ - frm.events.update_contact(frm) + + company_email: function(frm) { + frm.events.update_contact(frm); }, - user_id:function(frm){ - frm.events.update_contact(frm) + + user_id: function(frm) { + frm.events.update_contact(frm); }, - update_contact:function(frm){ + + update_contact: function(frm) { var prefered_email_fieldname = frappe.model.scrub(frm.doc.prefered_contact_email) || 'user_id'; frm.set_value("prefered_email", - frm.fields_dict[prefered_email_fieldname].value) + frm.fields_dict[prefered_email_fieldname].value); }, + status: function(frm) { return frm.call({ method: "deactivate_sales_person", @@ -81,19 +88,63 @@ frappe.ui.form.on('Employee',{ } }); }, + create_user: function(frm) { - if (!frm.doc.prefered_email) - { - frappe.throw(__("Please enter Preferred Contact Email")) + if (!frm.doc.prefered_email) { + frappe.throw(__("Please enter Preferred Contact Email")); } frappe.call({ method: "erpnext.hr.doctype.employee.employee.create_user", - args: { employee: frm.doc.name, email: frm.doc.prefered_email }, - callback: function(r) - { - frm.set_value("user_id", r.message) + args: { + employee: frm.doc.name, + email: frm.doc.prefered_email + }, + callback: function (r) { + frm.set_value("user_id", r.message); } }); } }); -cur_frm.cscript = new erpnext.hr.EmployeeController({frm: cur_frm}); + +cur_frm.cscript = new erpnext.hr.EmployeeController({ + frm: cur_frm +}); + + +frappe.tour['Employee'] = [ + { + fieldname: "first_name", + title: "First Name", + description: __("Enter First and Last name of Employee, based on Which Full Name will be updated. IN transactions, it will be Full Name which will be fetched.") + }, + { + fieldname: "company", + title: "Company", + description: __("Select a Company this Employee belongs to. Other HR features like Payroll. Expense Claims and Leaves for this Employee will be created for a given company only.") + }, + { + fieldname: "date_of_birth", + title: "Date of Birth", + description: __("Select Date of Birth. This will validate Employees age and prevent hiring of under-age staff.") + }, + { + fieldname: "date_of_joining", + title: "Date of Joining", + description: __("Select Date of joining. It will have impact on the first salary calculation, Leave allocation on pro-rata bases.") + }, + { + fieldname: "holiday_list", + title: "Holiday List", + description: __("Select a default Holiday List for this Employee. The days listed in Holiday List will not be counted in Leave Application.") + }, + { + fieldname: "reports_to", + title: "Reports To", + description: __("Here, you can select a senior of this Employee. Based on this, Organization Chart will be populated.") + }, + { + fieldname: "leave_approver", + title: "Leave Approver", + description: __("Select Leave Approver for an employee. The user one who will look after his/her Leave application") + }, +]; diff --git a/erpnext/hr/doctype/employee/employee_dashboard.py b/erpnext/hr/doctype/employee/employee_dashboard.py index ce307be60e8..a4c0af0a4bf 100644 --- a/erpnext/hr/doctype/employee/employee_dashboard.py +++ b/erpnext/hr/doctype/employee/employee_dashboard.py @@ -1,5 +1,3 @@ -from __future__ import unicode_literals - from frappe import _ diff --git a/erpnext/hr/doctype/employee/employee_reminders.py b/erpnext/hr/doctype/employee/employee_reminders.py index fc018664b46..559bd393e62 100644 --- a/erpnext/hr/doctype/employee/employee_reminders.py +++ b/erpnext/hr/doctype/employee/employee_reminders.py @@ -13,7 +13,7 @@ from erpnext.hr.utils import get_holidays_for_employee # HOLIDAY REMINDERS # ----------------- def send_reminders_in_advance_weekly(): - to_send_in_advance = int(frappe.db.get_single_value("HR Settings", "send_holiday_reminders") or 1) + to_send_in_advance = int(frappe.db.get_single_value("HR Settings", "send_holiday_reminders")) frequency = frappe.db.get_single_value("HR Settings", "frequency") if not (to_send_in_advance and frequency == "Weekly"): return @@ -21,7 +21,7 @@ def send_reminders_in_advance_weekly(): send_advance_holiday_reminders("Weekly") def send_reminders_in_advance_monthly(): - to_send_in_advance = int(frappe.db.get_single_value("HR Settings", "send_holiday_reminders") or 1) + to_send_in_advance = int(frappe.db.get_single_value("HR Settings", "send_holiday_reminders")) frequency = frappe.db.get_single_value("HR Settings", "frequency") if not (to_send_in_advance and frequency == "Monthly"): return @@ -79,7 +79,7 @@ def send_holidays_reminder_in_advance(employee, holidays): # ------------------ def send_birthday_reminders(): """Send Employee birthday reminders if no 'Stop Birthday Reminders' is not set.""" - to_send = int(frappe.db.get_single_value("HR Settings", "send_birthday_reminders") or 1) + to_send = int(frappe.db.get_single_value("HR Settings", "send_birthday_reminders")) if not to_send: return @@ -156,6 +156,8 @@ def get_employees_having_an_event_today(event_type): DAY({condition_column}) = DAY(%(today)s) AND MONTH({condition_column}) = MONTH(%(today)s) + AND + YEAR({condition_column}) < YEAR(%(today)s) AND `status` = 'Active' """, @@ -166,6 +168,8 @@ def get_employees_having_an_event_today(event_type): DATE_PART('day', {condition_column}) = date_part('day', %(today)s) AND DATE_PART('month', {condition_column}) = date_part('month', %(today)s) + AND + DATE_PART('year', {condition_column}) < date_part('year', %(today)s) AND "status" = 'Active' """, @@ -184,7 +188,7 @@ def get_employees_having_an_event_today(event_type): # -------------------------- def send_work_anniversary_reminders(): """Send Employee Work Anniversary Reminders if 'Send Work Anniversary Reminders' is checked""" - to_send = int(frappe.db.get_single_value("HR Settings", "send_work_anniversary_reminders") or 1) + to_send = int(frappe.db.get_single_value("HR Settings", "send_work_anniversary_reminders")) if not to_send: return diff --git a/erpnext/hr/doctype/employee/test_employee.py b/erpnext/hr/doctype/employee/test_employee.py index 8d6dfa2c1d2..8a2da0866e9 100644 --- a/erpnext/hr/doctype/employee/test_employee.py +++ b/erpnext/hr/doctype/employee/test_employee.py @@ -55,6 +55,7 @@ def make_employee(user, company=None, **kwargs): "email": user, "first_name": user, "new_password": "password", + "send_welcome_email": 0, "roles": [{"doctype": "Has Role", "role": "Employee"}] }).insert() diff --git a/erpnext/hr/doctype/employee_advance/employee_advance.js b/erpnext/hr/doctype/employee_advance/employee_advance.js index fa4b06aad37..7d1c7cbf4a8 100644 --- a/erpnext/hr/doctype/employee_advance/employee_advance.js +++ b/erpnext/hr/doctype/employee_advance/employee_advance.js @@ -73,7 +73,7 @@ frappe.ui.form.on('Employee Advance', { frm.trigger('make_return_entry'); }, __('Create')); } else if (frm.doc.repay_unclaimed_amount_from_salary == 1 && frappe.model.can_create("Additional Salary")) { - frm.add_custom_button(__("Deduction from salary"), function() { + frm.add_custom_button(__("Deduction from Salary"), function() { frm.events.make_deduction_via_additional_salary(frm); }, __('Create')); } diff --git a/erpnext/hr/doctype/employee_advance/employee_advance.json b/erpnext/hr/doctype/employee_advance/employee_advance.json index ea25aa720ad..04754530c3a 100644 --- a/erpnext/hr/doctype/employee_advance/employee_advance.json +++ b/erpnext/hr/doctype/employee_advance/employee_advance.json @@ -170,7 +170,7 @@ "default": "0", "fieldname": "repay_unclaimed_amount_from_salary", "fieldtype": "Check", - "label": "Repay unclaimed amount from salary" + "label": "Repay Unclaimed Amount from Salary" }, { "depends_on": "eval:cur_frm.doc.employee", @@ -200,10 +200,11 @@ ], "is_submittable": 1, "links": [], - "modified": "2021-03-31 22:31:53.746659", + "modified": "2021-09-11 18:38:38.617478", "modified_by": "Administrator", "module": "HR", "name": "Employee Advance", + "naming_rule": "By \"Naming Series\" field", "owner": "Administrator", "permissions": [ { diff --git a/erpnext/hr/doctype/employee_advance/employee_advance.py b/erpnext/hr/doctype/employee_advance/employee_advance.py index 87d42d34e39..8a8e8dba749 100644 --- a/erpnext/hr/doctype/employee_advance/employee_advance.py +++ b/erpnext/hr/doctype/employee_advance/employee_advance.py @@ -1,8 +1,6 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2017, Frappe Technologies Pvt. Ltd. and contributors # For license information, please see license.txt -from __future__ import unicode_literals import frappe from frappe import _ @@ -172,7 +170,10 @@ def get_paying_amount_paying_exchange_rate(payment_account, doc): @frappe.whitelist() def create_return_through_additional_salary(doc): import json - doc = frappe._dict(json.loads(doc)) + + if isinstance(doc, str): + doc = frappe._dict(json.loads(doc)) + additional_salary = frappe.new_doc('Additional Salary') additional_salary.employee = doc.employee additional_salary.currency = doc.currency diff --git a/erpnext/hr/doctype/employee_advance/employee_advance_dashboard.py b/erpnext/hr/doctype/employee_advance/employee_advance_dashboard.py index 17d5bd27a6e..9450258a8a2 100644 --- a/erpnext/hr/doctype/employee_advance/employee_advance_dashboard.py +++ b/erpnext/hr/doctype/employee_advance/employee_advance_dashboard.py @@ -1,6 +1,3 @@ -from __future__ import unicode_literals - - def get_data(): return { 'fieldname': 'employee_advance', diff --git a/erpnext/hr/doctype/employee_advance/test_employee_advance.py b/erpnext/hr/doctype/employee_advance/test_employee_advance.py index f8e5f535cb5..4ecfa60eb75 100644 --- a/erpnext/hr/doctype/employee_advance/test_employee_advance.py +++ b/erpnext/hr/doctype/employee_advance/test_employee_advance.py @@ -1,7 +1,5 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2017, Frappe Technologies Pvt. Ltd. and Contributors # See license.txt -from __future__ import unicode_literals import unittest @@ -12,8 +10,11 @@ import erpnext from erpnext.hr.doctype.employee.test_employee import make_employee from erpnext.hr.doctype.employee_advance.employee_advance import ( EmployeeAdvanceOverPayment, + create_return_through_additional_salary, make_bank_entry, ) +from erpnext.payroll.doctype.salary_component.test_salary_component import create_salary_component +from erpnext.payroll.doctype.salary_structure.test_salary_structure import make_salary_structure class TestEmployeeAdvance(unittest.TestCase): @@ -33,6 +34,46 @@ class TestEmployeeAdvance(unittest.TestCase): journal_entry1 = make_payment_entry(advance) self.assertRaises(EmployeeAdvanceOverPayment, journal_entry1.submit) + def test_repay_unclaimed_amount_from_salary(self): + employee_name = make_employee("_T@employe.advance") + advance = make_employee_advance(employee_name, {"repay_unclaimed_amount_from_salary": 1}) + + args = {"type": "Deduction"} + create_salary_component("Advance Salary - Deduction", **args) + make_salary_structure("Test Additional Salary for Advance Return", "Monthly", employee=employee_name) + + # additional salary for 700 first + advance.reload() + additional_salary = create_return_through_additional_salary(advance) + additional_salary.salary_component = "Advance Salary - Deduction" + additional_salary.payroll_date = nowdate() + additional_salary.amount = 700 + additional_salary.insert() + additional_salary.submit() + + advance.reload() + self.assertEqual(advance.return_amount, 700) + + # additional salary for remaining 300 + additional_salary = create_return_through_additional_salary(advance) + additional_salary.salary_component = "Advance Salary - Deduction" + additional_salary.payroll_date = nowdate() + additional_salary.amount = 300 + additional_salary.insert() + additional_salary.submit() + + advance.reload() + self.assertEqual(advance.return_amount, 1000) + + # update advance return amount on additional salary cancellation + additional_salary.cancel() + advance.reload() + self.assertEqual(advance.return_amount, 700) + + def tearDown(self): + frappe.db.rollback() + + def make_payment_entry(advance): journal_entry = frappe.get_doc(make_bank_entry("Employee Advance", advance.name)) journal_entry.cheque_no = "123123" @@ -41,7 +82,7 @@ def make_payment_entry(advance): return journal_entry -def make_employee_advance(employee_name): +def make_employee_advance(employee_name, args=None): doc = frappe.new_doc("Employee Advance") doc.employee = employee_name doc.company = "_Test company" @@ -51,6 +92,10 @@ def make_employee_advance(employee_name): doc.advance_amount = 1000 doc.posting_date = nowdate() doc.advance_account = "_Test Employee Advance - _TC" + + if args: + doc.update(args) + doc.insert() doc.submit() diff --git a/erpnext/hr/doctype/employee_attendance_tool/employee_attendance_tool.py b/erpnext/hr/doctype/employee_attendance_tool/employee_attendance_tool.py index 7c751a47a6b..af2ca50b78a 100644 --- a/erpnext/hr/doctype/employee_attendance_tool/employee_attendance_tool.py +++ b/erpnext/hr/doctype/employee_attendance_tool/employee_attendance_tool.py @@ -1,8 +1,6 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and contributors # For license information, please see license.txt -from __future__ import unicode_literals import json @@ -55,8 +53,7 @@ def mark_employee_attendance(employee_list, status, date, leave_type=None, compa else: leave_type = None - if not company: - company = frappe.db.get_value("Employee", employee['employee'], "Company") + company = frappe.db.get_value("Employee", employee['employee'], "Company", cache=True) attendance=frappe.get_doc(dict( doctype='Attendance', @@ -68,4 +65,4 @@ def mark_employee_attendance(employee_list, status, date, leave_type=None, compa company=company )) attendance.insert() - attendance.submit() + attendance.submit() \ No newline at end of file diff --git a/erpnext/hr/doctype/employee_boarding_activity/employee_boarding_activity.py b/erpnext/hr/doctype/employee_boarding_activity/employee_boarding_activity.py index 48c85f48aa2..e824081327d 100644 --- a/erpnext/hr/doctype/employee_boarding_activity/employee_boarding_activity.py +++ b/erpnext/hr/doctype/employee_boarding_activity/employee_boarding_activity.py @@ -1,8 +1,6 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2018, Frappe Technologies Pvt. Ltd. and contributors # For license information, please see license.txt -from __future__ import unicode_literals from frappe.model.document import Document diff --git a/erpnext/hr/doctype/employee_checkin/employee_checkin.py b/erpnext/hr/doctype/employee_checkin/employee_checkin.py index 1ae9b1fa829..c1d4ac7fded 100644 --- a/erpnext/hr/doctype/employee_checkin/employee_checkin.py +++ b/erpnext/hr/doctype/employee_checkin/employee_checkin.py @@ -1,8 +1,6 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2019, Frappe Technologies Pvt. Ltd. and contributors # For license information, please see license.txt -from __future__ import unicode_literals import frappe from frappe import _ diff --git a/erpnext/hr/doctype/employee_checkin/test_employee_checkin.py b/erpnext/hr/doctype/employee_checkin/test_employee_checkin.py index 71c6498dd7c..254bf9e2569 100644 --- a/erpnext/hr/doctype/employee_checkin/test_employee_checkin.py +++ b/erpnext/hr/doctype/employee_checkin/test_employee_checkin.py @@ -1,7 +1,5 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2019, Frappe Technologies Pvt. Ltd. and Contributors # See license.txt -from __future__ import unicode_literals import unittest from datetime import timedelta diff --git a/erpnext/hr/doctype/employee_education/__init__.py b/erpnext/hr/doctype/employee_education/__init__.py index baffc488252..e69de29bb2d 100644 --- a/erpnext/hr/doctype/employee_education/__init__.py +++ b/erpnext/hr/doctype/employee_education/__init__.py @@ -1 +0,0 @@ -from __future__ import unicode_literals diff --git a/erpnext/hr/doctype/employee_education/employee_education.py b/erpnext/hr/doctype/employee_education/employee_education.py index cadf5d64594..ded583bf01d 100644 --- a/erpnext/hr/doctype/employee_education/employee_education.py +++ b/erpnext/hr/doctype/employee_education/employee_education.py @@ -1,7 +1,6 @@ # Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors # License: GNU General Public License v3. See license.txt -from __future__ import unicode_literals from frappe.model.document import Document diff --git a/erpnext/hr/doctype/employee_external_work_history/__init__.py b/erpnext/hr/doctype/employee_external_work_history/__init__.py index baffc488252..e69de29bb2d 100644 --- a/erpnext/hr/doctype/employee_external_work_history/__init__.py +++ b/erpnext/hr/doctype/employee_external_work_history/__init__.py @@ -1 +0,0 @@ -from __future__ import unicode_literals diff --git a/erpnext/hr/doctype/employee_external_work_history/employee_external_work_history.py b/erpnext/hr/doctype/employee_external_work_history/employee_external_work_history.py index 4d0e8d9b74a..d594fbf0f0c 100644 --- a/erpnext/hr/doctype/employee_external_work_history/employee_external_work_history.py +++ b/erpnext/hr/doctype/employee_external_work_history/employee_external_work_history.py @@ -1,7 +1,6 @@ # Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors # License: GNU General Public License v3. See license.txt -from __future__ import unicode_literals from frappe.model.document import Document diff --git a/erpnext/hr/doctype/employee_grade/employee_grade.py b/erpnext/hr/doctype/employee_grade/employee_grade.py index b097038b5c2..41b7915c95a 100644 --- a/erpnext/hr/doctype/employee_grade/employee_grade.py +++ b/erpnext/hr/doctype/employee_grade/employee_grade.py @@ -1,8 +1,6 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2018, Frappe Technologies Pvt. Ltd. and contributors # For license information, please see license.txt -from __future__ import unicode_literals from frappe.model.document import Document diff --git a/erpnext/hr/doctype/employee_grade/employee_grade_dashboard.py b/erpnext/hr/doctype/employee_grade/employee_grade_dashboard.py index 92d9fa082c9..6825dae2506 100644 --- a/erpnext/hr/doctype/employee_grade/employee_grade_dashboard.py +++ b/erpnext/hr/doctype/employee_grade/employee_grade_dashboard.py @@ -1,6 +1,3 @@ -from __future__ import unicode_literals - - def get_data(): return { 'transactions': [ diff --git a/erpnext/hr/doctype/employee_grade/test_employee_grade.py b/erpnext/hr/doctype/employee_grade/test_employee_grade.py index cd4fcb5aeb4..a70d6853487 100644 --- a/erpnext/hr/doctype/employee_grade/test_employee_grade.py +++ b/erpnext/hr/doctype/employee_grade/test_employee_grade.py @@ -1,7 +1,5 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2018, Frappe Technologies Pvt. Ltd. and Contributors # See license.txt -from __future__ import unicode_literals import unittest diff --git a/erpnext/hr/doctype/employee_group/employee_group.py b/erpnext/hr/doctype/employee_group/employee_group.py index b2fe5eb3ad6..c4ce083c942 100644 --- a/erpnext/hr/doctype/employee_group/employee_group.py +++ b/erpnext/hr/doctype/employee_group/employee_group.py @@ -1,8 +1,6 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2018, Frappe Technologies Pvt. Ltd. and contributors # For license information, please see license.txt -from __future__ import unicode_literals from frappe.model.document import Document diff --git a/erpnext/hr/doctype/employee_group/test_employee_group.py b/erpnext/hr/doctype/employee_group/test_employee_group.py index 053e840740a..a87f4007bd8 100644 --- a/erpnext/hr/doctype/employee_group/test_employee_group.py +++ b/erpnext/hr/doctype/employee_group/test_employee_group.py @@ -1,7 +1,5 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2018, Frappe Technologies Pvt. Ltd. and Contributors # See license.txt -from __future__ import unicode_literals import unittest diff --git a/erpnext/hr/doctype/employee_group_table/employee_group_table.py b/erpnext/hr/doctype/employee_group_table/employee_group_table.py index d9407a96fa6..adf6ca2668c 100644 --- a/erpnext/hr/doctype/employee_group_table/employee_group_table.py +++ b/erpnext/hr/doctype/employee_group_table/employee_group_table.py @@ -1,8 +1,6 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2018, Frappe Technologies Pvt. Ltd. and contributors # For license information, please see license.txt -from __future__ import unicode_literals from frappe.model.document import Document diff --git a/erpnext/hr/doctype/employee_health_insurance/employee_health_insurance.py b/erpnext/hr/doctype/employee_health_insurance/employee_health_insurance.py index 4f2d1a07653..4a8c437d64c 100644 --- a/erpnext/hr/doctype/employee_health_insurance/employee_health_insurance.py +++ b/erpnext/hr/doctype/employee_health_insurance/employee_health_insurance.py @@ -1,8 +1,6 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2018, Frappe Technologies Pvt. Ltd. and contributors # For license information, please see license.txt -from __future__ import unicode_literals from frappe.model.document import Document diff --git a/erpnext/hr/doctype/employee_health_insurance/test_employee_health_insurance.py b/erpnext/hr/doctype/employee_health_insurance/test_employee_health_insurance.py index 38e3ee316bb..4f042b70798 100644 --- a/erpnext/hr/doctype/employee_health_insurance/test_employee_health_insurance.py +++ b/erpnext/hr/doctype/employee_health_insurance/test_employee_health_insurance.py @@ -1,7 +1,5 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2018, Frappe Technologies Pvt. Ltd. and Contributors # See license.txt -from __future__ import unicode_literals import unittest diff --git a/erpnext/hr/doctype/employee_internal_work_history/__init__.py b/erpnext/hr/doctype/employee_internal_work_history/__init__.py index baffc488252..e69de29bb2d 100644 --- a/erpnext/hr/doctype/employee_internal_work_history/__init__.py +++ b/erpnext/hr/doctype/employee_internal_work_history/__init__.py @@ -1 +0,0 @@ -from __future__ import unicode_literals diff --git a/erpnext/hr/doctype/employee_internal_work_history/employee_internal_work_history.py b/erpnext/hr/doctype/employee_internal_work_history/employee_internal_work_history.py index 6076abb3468..6225de60148 100644 --- a/erpnext/hr/doctype/employee_internal_work_history/employee_internal_work_history.py +++ b/erpnext/hr/doctype/employee_internal_work_history/employee_internal_work_history.py @@ -1,7 +1,6 @@ # Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors # License: GNU General Public License v3. See license.txt -from __future__ import unicode_literals from frappe.model.document import Document diff --git a/erpnext/hr/doctype/employee_onboarding/employee_onboarding.py b/erpnext/hr/doctype/employee_onboarding/employee_onboarding.py index e96447b7976..eba2a03193c 100644 --- a/erpnext/hr/doctype/employee_onboarding/employee_onboarding.py +++ b/erpnext/hr/doctype/employee_onboarding/employee_onboarding.py @@ -1,8 +1,6 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2018, Frappe Technologies Pvt. Ltd. and contributors # For license information, please see license.txt -from __future__ import unicode_literals import frappe from frappe import _ diff --git a/erpnext/hr/doctype/employee_onboarding/test_employee_onboarding.py b/erpnext/hr/doctype/employee_onboarding/test_employee_onboarding.py index eae600db7b8..cb1b56048b7 100644 --- a/erpnext/hr/doctype/employee_onboarding/test_employee_onboarding.py +++ b/erpnext/hr/doctype/employee_onboarding/test_employee_onboarding.py @@ -1,7 +1,5 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2018, Frappe Technologies Pvt. Ltd. and Contributors # See license.txt -from __future__ import unicode_literals import unittest @@ -71,6 +69,7 @@ def get_job_applicant(): applicant = frappe.new_doc('Job Applicant') applicant.applicant_name = 'Test Researcher' applicant.email_id = 'test@researcher.com' + applicant.designation = 'Researcher' applicant.status = 'Open' applicant.cover_letter = 'I am a great Researcher.' applicant.insert() diff --git a/erpnext/hr/doctype/employee_onboarding_template/employee_onboarding_template.py b/erpnext/hr/doctype/employee_onboarding_template/employee_onboarding_template.py index a46b3cdda39..199013a5a13 100644 --- a/erpnext/hr/doctype/employee_onboarding_template/employee_onboarding_template.py +++ b/erpnext/hr/doctype/employee_onboarding_template/employee_onboarding_template.py @@ -1,8 +1,6 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2018, Frappe Technologies Pvt. Ltd. and contributors # For license information, please see license.txt -from __future__ import unicode_literals from frappe.model.document import Document diff --git a/erpnext/hr/doctype/employee_onboarding_template/employee_onboarding_template_dashboard.py b/erpnext/hr/doctype/employee_onboarding_template/employee_onboarding_template_dashboard.py index 1d2e8ae18db..3b846a0e406 100644 --- a/erpnext/hr/doctype/employee_onboarding_template/employee_onboarding_template_dashboard.py +++ b/erpnext/hr/doctype/employee_onboarding_template/employee_onboarding_template_dashboard.py @@ -1,6 +1,3 @@ -from __future__ import unicode_literals - - def get_data(): return { 'fieldname': 'employee_onboarding_template', diff --git a/erpnext/hr/doctype/employee_onboarding_template/test_employee_onboarding_template.py b/erpnext/hr/doctype/employee_onboarding_template/test_employee_onboarding_template.py index 92a328b71ef..db09011c878 100644 --- a/erpnext/hr/doctype/employee_onboarding_template/test_employee_onboarding_template.py +++ b/erpnext/hr/doctype/employee_onboarding_template/test_employee_onboarding_template.py @@ -1,7 +1,5 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2018, Frappe Technologies Pvt. Ltd. and Contributors # See license.txt -from __future__ import unicode_literals import unittest diff --git a/erpnext/hr/doctype/employee_promotion/employee_promotion.py b/erpnext/hr/doctype/employee_promotion/employee_promotion.py index 164d48b8952..cf6156e3264 100644 --- a/erpnext/hr/doctype/employee_promotion/employee_promotion.py +++ b/erpnext/hr/doctype/employee_promotion/employee_promotion.py @@ -1,15 +1,13 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2018, Frappe Technologies Pvt. Ltd. and contributors # For license information, please see license.txt -from __future__ import unicode_literals import frappe from frappe import _ from frappe.model.document import Document from frappe.utils import getdate -from erpnext.hr.utils import update_employee, validate_active_employee +from erpnext.hr.utils import update_employee_work_history, validate_active_employee class EmployeePromotion(Document): @@ -23,10 +21,10 @@ class EmployeePromotion(Document): def on_submit(self): employee = frappe.get_doc("Employee", self.employee) - employee = update_employee(employee, self.promotion_details, date=self.promotion_date) + employee = update_employee_work_history(employee, self.promotion_details, date=self.promotion_date) employee.save() def on_cancel(self): employee = frappe.get_doc("Employee", self.employee) - employee = update_employee(employee, self.promotion_details, cancel=True) + employee = update_employee_work_history(employee, self.promotion_details, cancel=True) employee.save() diff --git a/erpnext/hr/doctype/employee_promotion/test_employee_promotion.py b/erpnext/hr/doctype/employee_promotion/test_employee_promotion.py index 39af6ff7cc7..fc9d195a3f3 100644 --- a/erpnext/hr/doctype/employee_promotion/test_employee_promotion.py +++ b/erpnext/hr/doctype/employee_promotion/test_employee_promotion.py @@ -1,7 +1,5 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2018, Frappe Technologies Pvt. Ltd. and Contributors # See license.txt -from __future__ import unicode_literals import unittest diff --git a/erpnext/hr/doctype/employee_property_history/employee_property_history.py b/erpnext/hr/doctype/employee_property_history/employee_property_history.py index 9e2549284fb..345899e43cf 100644 --- a/erpnext/hr/doctype/employee_property_history/employee_property_history.py +++ b/erpnext/hr/doctype/employee_property_history/employee_property_history.py @@ -1,8 +1,6 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2018, Frappe Technologies Pvt. Ltd. and contributors # For license information, please see license.txt -from __future__ import unicode_literals from frappe.model.document import Document diff --git a/erpnext/hr/doctype/employee_referral/employee_referral.py b/erpnext/hr/doctype/employee_referral/employee_referral.py index 5cb5bb5fd3a..eaa42c7b4ca 100644 --- a/erpnext/hr/doctype/employee_referral/employee_referral.py +++ b/erpnext/hr/doctype/employee_referral/employee_referral.py @@ -1,8 +1,6 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2021, Frappe Technologies Pvt. Ltd. and contributors # For license information, please see license.txt -from __future__ import unicode_literals import frappe from frappe import _ @@ -38,8 +36,10 @@ def create_job_applicant(source_name, target_doc=None): status = "Open" job_applicant = frappe.new_doc("Job Applicant") + job_applicant.source = "Employee Referral" job_applicant.employee_referral = emp_ref.name job_applicant.status = status + job_applicant.designation = emp_ref.for_designation job_applicant.applicant_name = emp_ref.full_name job_applicant.email_id = emp_ref.email job_applicant.phone_number = emp_ref.contact_no @@ -60,9 +60,8 @@ def create_job_applicant(source_name, target_doc=None): def create_additional_salary(doc): import json - from six import string_types - if isinstance(doc, string_types): + if isinstance(doc, str): doc = frappe._dict(json.loads(doc)) if not frappe.db.exists("Additional Salary", {"ref_docname": doc.name}): diff --git a/erpnext/hr/doctype/employee_referral/employee_referral_dashboard.py b/erpnext/hr/doctype/employee_referral/employee_referral_dashboard.py index 85d6c2089b8..07c2402e1a4 100644 --- a/erpnext/hr/doctype/employee_referral/employee_referral_dashboard.py +++ b/erpnext/hr/doctype/employee_referral/employee_referral_dashboard.py @@ -1,6 +1,3 @@ -from __future__ import unicode_literals - - def get_data(): return { 'fieldname': 'employee_referral', diff --git a/erpnext/hr/doctype/employee_referral/test_employee_referral.py b/erpnext/hr/doctype/employee_referral/test_employee_referral.py index d0ee2fcdea7..529e3551454 100644 --- a/erpnext/hr/doctype/employee_referral/test_employee_referral.py +++ b/erpnext/hr/doctype/employee_referral/test_employee_referral.py @@ -1,7 +1,5 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2021, Frappe Technologies Pvt. Ltd. and Contributors # See license.txt -from __future__ import unicode_literals import unittest @@ -17,6 +15,11 @@ from erpnext.hr.doctype.employee_referral.employee_referral import ( class TestEmployeeReferral(unittest.TestCase): + + def setUp(self): + frappe.db.sql("DELETE FROM `tabJob Applicant`") + frappe.db.sql("DELETE FROM `tabEmployee Referral`") + def test_workflow_and_status_sync(self): emp_ref = create_employee_referral() @@ -50,6 +53,10 @@ class TestEmployeeReferral(unittest.TestCase): add_sal = create_additional_salary(emp_ref) self.assertTrue(add_sal.ref_docname, emp_ref.name) + def tearDown(self): + frappe.db.sql("DELETE FROM `tabJob Applicant`") + frappe.db.sql("DELETE FROM `tabEmployee Referral`") + def create_employee_referral(): emp_ref = frappe.new_doc("Employee Referral") diff --git a/erpnext/hr/doctype/employee_separation/employee_separation.py b/erpnext/hr/doctype/employee_separation/employee_separation.py index ad279e8ce4c..915e9a876e7 100644 --- a/erpnext/hr/doctype/employee_separation/employee_separation.py +++ b/erpnext/hr/doctype/employee_separation/employee_separation.py @@ -1,8 +1,6 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2018, Frappe Technologies Pvt. Ltd. and contributors # For license information, please see license.txt -from __future__ import unicode_literals from erpnext.controllers.employee_boarding_controller import EmployeeBoardingController diff --git a/erpnext/hr/doctype/employee_separation/test_employee_separation.py b/erpnext/hr/doctype/employee_separation/test_employee_separation.py index c7068dd78d0..f83c1e57b85 100644 --- a/erpnext/hr/doctype/employee_separation/test_employee_separation.py +++ b/erpnext/hr/doctype/employee_separation/test_employee_separation.py @@ -1,7 +1,5 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2018, Frappe Technologies Pvt. Ltd. and Contributors # See license.txt -from __future__ import unicode_literals import unittest diff --git a/erpnext/hr/doctype/employee_separation_template/employee_separation_template.py b/erpnext/hr/doctype/employee_separation_template/employee_separation_template.py index 7a263dcac10..70b84b1755d 100644 --- a/erpnext/hr/doctype/employee_separation_template/employee_separation_template.py +++ b/erpnext/hr/doctype/employee_separation_template/employee_separation_template.py @@ -1,8 +1,6 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2018, Frappe Technologies Pvt. Ltd. and contributors # For license information, please see license.txt -from __future__ import unicode_literals from frappe.model.document import Document diff --git a/erpnext/hr/doctype/employee_separation_template/employee_separation_template_dashboard.py b/erpnext/hr/doctype/employee_separation_template/employee_separation_template_dashboard.py index 970ba26d794..6e2a83eaa70 100644 --- a/erpnext/hr/doctype/employee_separation_template/employee_separation_template_dashboard.py +++ b/erpnext/hr/doctype/employee_separation_template/employee_separation_template_dashboard.py @@ -1,6 +1,3 @@ -from __future__ import unicode_literals - - def get_data(): return { 'fieldname': 'employee_separation_template', diff --git a/erpnext/hr/doctype/employee_separation_template/test_employee_separation_template.py b/erpnext/hr/doctype/employee_separation_template/test_employee_separation_template.py index 4c91a791038..6a0c9479db6 100644 --- a/erpnext/hr/doctype/employee_separation_template/test_employee_separation_template.py +++ b/erpnext/hr/doctype/employee_separation_template/test_employee_separation_template.py @@ -1,7 +1,5 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2018, Frappe Technologies Pvt. Ltd. and Contributors # See license.txt -from __future__ import unicode_literals import unittest diff --git a/erpnext/hr/doctype/employee_skill/employee_skill.py b/erpnext/hr/doctype/employee_skill/employee_skill.py index 6f860c6c599..13bee342532 100644 --- a/erpnext/hr/doctype/employee_skill/employee_skill.py +++ b/erpnext/hr/doctype/employee_skill/employee_skill.py @@ -1,8 +1,6 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2019, Frappe Technologies Pvt. Ltd. and contributors # For license information, please see license.txt -from __future__ import unicode_literals # import frappe from frappe.model.document import Document diff --git a/erpnext/hr/doctype/employee_skill_map/employee_skill_map.py b/erpnext/hr/doctype/employee_skill_map/employee_skill_map.py index d93c22f2ab8..ea7da9edf9c 100644 --- a/erpnext/hr/doctype/employee_skill_map/employee_skill_map.py +++ b/erpnext/hr/doctype/employee_skill_map/employee_skill_map.py @@ -1,8 +1,6 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2019, Frappe Technologies Pvt. Ltd. and contributors # For license information, please see license.txt -from __future__ import unicode_literals # import frappe from frappe.model.document import Document diff --git a/erpnext/hr/doctype/employee_training/employee_training.py b/erpnext/hr/doctype/employee_training/employee_training.py index 068116a77f6..cd92dd609f9 100644 --- a/erpnext/hr/doctype/employee_training/employee_training.py +++ b/erpnext/hr/doctype/employee_training/employee_training.py @@ -1,8 +1,6 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2019, Frappe Technologies Pvt. Ltd. and contributors # For license information, please see license.txt -from __future__ import unicode_literals # import frappe from frappe.model.document import Document diff --git a/erpnext/hr/doctype/employee_transfer/employee_transfer.py b/erpnext/hr/doctype/employee_transfer/employee_transfer.py index b1f66098f0d..f927d413ae3 100644 --- a/erpnext/hr/doctype/employee_transfer/employee_transfer.py +++ b/erpnext/hr/doctype/employee_transfer/employee_transfer.py @@ -1,15 +1,13 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2018, Frappe Technologies Pvt. Ltd. and contributors # For license information, please see license.txt -from __future__ import unicode_literals import frappe from frappe import _ from frappe.model.document import Document from frappe.utils import getdate -from erpnext.hr.utils import update_employee +from erpnext.hr.utils import update_employee_work_history class EmployeeTransfer(Document): @@ -24,7 +22,7 @@ class EmployeeTransfer(Document): new_employee = frappe.copy_doc(employee) new_employee.name = None new_employee.employee_number = None - new_employee = update_employee(new_employee, self.transfer_details, date=self.transfer_date) + new_employee = update_employee_work_history(new_employee, self.transfer_details, date=self.transfer_date) if self.new_company and self.company != self.new_company: new_employee.internal_work_history = [] new_employee.date_of_joining = self.transfer_date @@ -39,7 +37,7 @@ class EmployeeTransfer(Document): employee.db_set("relieving_date", self.transfer_date) employee.db_set("status", "Left") else: - employee = update_employee(employee, self.transfer_details, date=self.transfer_date) + employee = update_employee_work_history(employee, self.transfer_details, date=self.transfer_date) if self.new_company and self.company != self.new_company: employee.company = self.new_company employee.date_of_joining = self.transfer_date @@ -56,7 +54,7 @@ class EmployeeTransfer(Document): employee.status = "Active" employee.relieving_date = '' else: - employee = update_employee(employee, self.transfer_details, cancel=True) + employee = update_employee_work_history(employee, self.transfer_details, date=self.transfer_date, cancel=True) if self.new_company != self.company: employee.company = self.company employee.save() diff --git a/erpnext/hr/doctype/employee_transfer/test_employee_transfer.py b/erpnext/hr/doctype/employee_transfer/test_employee_transfer.py index ad2f3ade054..287dfba35b3 100644 --- a/erpnext/hr/doctype/employee_transfer/test_employee_transfer.py +++ b/erpnext/hr/doctype/employee_transfer/test_employee_transfer.py @@ -1,9 +1,8 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2018, Frappe Technologies Pvt. Ltd. and Contributors # See license.txt -from __future__ import unicode_literals import unittest +from datetime import date import frappe from frappe.utils import add_days, getdate @@ -15,7 +14,12 @@ class TestEmployeeTransfer(unittest.TestCase): def setUp(self): make_employee("employee2@transfers.com") make_employee("employee3@transfers.com") - frappe.db.sql("""delete from `tabEmployee Transfer`""") + create_company() + create_employee() + create_employee_transfer() + + def tearDown(self): + frappe.db.rollback() def test_submit_before_transfer_date(self): transfer_obj = frappe.get_doc({ @@ -57,3 +61,77 @@ class TestEmployeeTransfer(unittest.TestCase): self.assertTrue(transfer.new_employee_id) self.assertEqual(frappe.get_value("Employee", transfer.new_employee_id, "status"), "Active") self.assertEqual(frappe.get_value("Employee", transfer.employee, "status"), "Left") + + def test_employee_history(self): + name = frappe.get_value("Employee", {"first_name": "John", "company": "Test Company"}, "name") + doc = frappe.get_doc("Employee",name) + count = 0 + department = ["Accounts - TC", "Management - TC"] + designation = ["Accountant", "Manager"] + dt = [getdate("01-10-2021"), date.today()] + + for data in doc.internal_work_history: + self.assertEqual(data.department, department[count]) + self.assertEqual(data.designation, designation[count]) + self.assertEqual(data.from_date, dt[count]) + count = count + 1 + + data = frappe.db.get_list("Employee Transfer", filters={"employee":name}, fields=["*"]) + doc = frappe.get_doc("Employee Transfer", data[0]["name"]) + doc.cancel() + employee_doc = frappe.get_doc("Employee",name) + + for data in employee_doc.internal_work_history: + self.assertEqual(data.designation, designation[0]) + self.assertEqual(data.department, department[0]) + self.assertEqual(data.from_date, dt[0]) + +def create_employee(): + doc = frappe.get_doc({ + "doctype": "Employee", + "first_name": "John", + "company": "Test Company", + "gender": "Male", + "date_of_birth": getdate("30-09-1980"), + "date_of_joining": getdate("01-10-2021"), + "department": "Accounts - TC", + "designation": "Accountant" + }) + + doc.save() + +def create_company(): + exists = frappe.db.exists("Company", "Test Company") + if not exists: + doc = frappe.get_doc({ + "doctype": "Company", + "company_name": "Test Company", + "default_currency": "INR", + "country": "India" + }) + + doc.save() + +def create_employee_transfer(): + doc = frappe.get_doc({ + "doctype": "Employee Transfer", + "employee": frappe.get_value("Employee", {"first_name": "John", "company": "Test Company"}, "name"), + "transfer_date": date.today(), + "transfer_details": [ + { + "property": "Designation", + "current": "Accountant", + "new": "Manager", + "fieldname": "designation" + }, + { + "property": "Department", + "current": "Accounts - TC", + "new": "Management - TC", + "fieldname": "department" + } + ] + }) + + doc.save() + doc.submit() \ No newline at end of file diff --git a/erpnext/hr/doctype/employee_transfer_property/employee_transfer_property.py b/erpnext/hr/doctype/employee_transfer_property/employee_transfer_property.py index f67fd7c6564..76e200602f5 100644 --- a/erpnext/hr/doctype/employee_transfer_property/employee_transfer_property.py +++ b/erpnext/hr/doctype/employee_transfer_property/employee_transfer_property.py @@ -1,8 +1,6 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2018, Frappe Technologies Pvt. Ltd. and contributors # For license information, please see license.txt -from __future__ import unicode_literals from frappe.model.document import Document diff --git a/erpnext/hr/doctype/employee_transfer_property/test_employee_transfer_property.py b/erpnext/hr/doctype/employee_transfer_property/test_employee_transfer_property.py index 287dac66f10..981d46f57d2 100644 --- a/erpnext/hr/doctype/employee_transfer_property/test_employee_transfer_property.py +++ b/erpnext/hr/doctype/employee_transfer_property/test_employee_transfer_property.py @@ -1,7 +1,5 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2018, Frappe Technologies Pvt. Ltd. and Contributors # See license.txt -from __future__ import unicode_literals import unittest diff --git a/erpnext/hr/doctype/employment_type/__init__.py b/erpnext/hr/doctype/employment_type/__init__.py index baffc488252..e69de29bb2d 100644 --- a/erpnext/hr/doctype/employment_type/__init__.py +++ b/erpnext/hr/doctype/employment_type/__init__.py @@ -1 +0,0 @@ -from __future__ import unicode_literals diff --git a/erpnext/hr/doctype/employment_type/employment_type.py b/erpnext/hr/doctype/employment_type/employment_type.py index e2a55570fd9..b2262c0c585 100644 --- a/erpnext/hr/doctype/employment_type/employment_type.py +++ b/erpnext/hr/doctype/employment_type/employment_type.py @@ -1,7 +1,6 @@ # Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors # License: GNU General Public License v3. See license.txt -from __future__ import unicode_literals from frappe.model.document import Document diff --git a/erpnext/hr/doctype/employment_type/test_employment_type.py b/erpnext/hr/doctype/employment_type/test_employment_type.py index 2ba4e8c1a46..c43f9636c70 100644 --- a/erpnext/hr/doctype/employment_type/test_employment_type.py +++ b/erpnext/hr/doctype/employment_type/test_employment_type.py @@ -1,6 +1,5 @@ # Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors # License: GNU General Public License v3. See license.txt -from __future__ import unicode_literals import frappe diff --git a/erpnext/healthcare/doctype/clinical_procedure_item/__init__.py b/erpnext/hr/doctype/expected_skill_set/__init__.py similarity index 100% rename from erpnext/healthcare/doctype/clinical_procedure_item/__init__.py rename to erpnext/hr/doctype/expected_skill_set/__init__.py diff --git a/erpnext/healthcare/doctype/exercise_type_step/exercise_type_step.json b/erpnext/hr/doctype/expected_skill_set/expected_skill_set.json similarity index 54% rename from erpnext/healthcare/doctype/exercise_type_step/exercise_type_step.json rename to erpnext/hr/doctype/expected_skill_set/expected_skill_set.json index b37ff007cb9..899f5bd0ff4 100644 --- a/erpnext/healthcare/doctype/exercise_type_step/exercise_type_step.json +++ b/erpnext/hr/doctype/expected_skill_set/expected_skill_set.json @@ -1,43 +1,39 @@ { "actions": [], - "creation": "2020-03-31 23:01:18.761967", + "creation": "2021-04-12 13:05:06.741330", "doctype": "DocType", "editable_grid": 1, "engine": "InnoDB", "field_order": [ - "title", - "image", + "skill", "description" ], "fields": [ { - "fieldname": "title", - "fieldtype": "Data", + "fieldname": "skill", + "fieldtype": "Link", "in_list_view": 1, - "label": "Title", + "label": "Skill", + "options": "Skill", "reqd": 1 }, { - "fieldname": "image", - "fieldtype": "Attach Image", - "label": "Image" - }, - { + "fetch_from": "skill.description", "fieldname": "description", - "fieldtype": "Long Text", + "fieldtype": "Small Text", "in_list_view": 1, "label": "Description" } ], + "index_web_pages_for_search": 1, "istable": 1, "links": [], - "modified": "2020-04-02 20:39:34.258512", + "modified": "2021-04-12 14:26:33.062549", "modified_by": "Administrator", - "module": "Healthcare", - "name": "Exercise Type Step", + "module": "HR", + "name": "Expected Skill Set", "owner": "Administrator", "permissions": [], - "quick_entry": 1, "sort_field": "modified", "sort_order": "DESC", "track_changes": 1 diff --git a/erpnext/healthcare/doctype/appointment_type_service_item/appointment_type_service_item.py b/erpnext/hr/doctype/expected_skill_set/expected_skill_set.py similarity index 63% rename from erpnext/healthcare/doctype/appointment_type_service_item/appointment_type_service_item.py rename to erpnext/hr/doctype/expected_skill_set/expected_skill_set.py index 026d5d79fd9..0062ba91a19 100644 --- a/erpnext/healthcare/doctype/appointment_type_service_item/appointment_type_service_item.py +++ b/erpnext/hr/doctype/expected_skill_set/expected_skill_set.py @@ -1,12 +1,10 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2021, Frappe Technologies Pvt. Ltd. and contributors # For license information, please see license.txt -from __future__ import unicode_literals # import frappe from frappe.model.document import Document -class AppointmentTypeServiceItem(Document): +class ExpectedSkillSet(Document): pass diff --git a/erpnext/hr/doctype/expense_claim/__init__.py b/erpnext/hr/doctype/expense_claim/__init__.py index baffc488252..e69de29bb2d 100644 --- a/erpnext/hr/doctype/expense_claim/__init__.py +++ b/erpnext/hr/doctype/expense_claim/__init__.py @@ -1 +0,0 @@ -from __future__ import unicode_literals diff --git a/erpnext/hr/doctype/expense_claim/expense_claim.js b/erpnext/hr/doctype/expense_claim/expense_claim.js index 3c4c672816c..665556301bb 100644 --- a/erpnext/hr/doctype/expense_claim/expense_claim.js +++ b/erpnext/hr/doctype/expense_claim/expense_claim.js @@ -10,6 +10,26 @@ frappe.ui.form.on('Expense Claim', { }, company: function(frm) { erpnext.accounts.dimensions.update_dimension(frm, frm.doctype); + var expenses = frm.doc.expenses; + for (var i = 0; i < expenses.length; i++) { + var expense = expenses[i]; + if (!expense.expense_type) { + continue; + } + frappe.call({ + method: "erpnext.hr.doctype.expense_claim.expense_claim.get_expense_claim_account_and_cost_center", + args: { + "expense_claim_type": expense.expense_type, + "company": frm.doc.company + }, + callback: function(r) { + if (r.message) { + expense.default_account = r.message.account; + expense.cost_center = r.message.cost_center; + } + } + }); + } }, }); @@ -369,7 +389,9 @@ frappe.ui.form.on("Expense Claim Detail", { sanctioned_amount: function(frm, cdt, cdn) { cur_frm.cscript.calculate_total(frm.doc, cdt, cdn); frm.trigger("get_taxes"); + frm.trigger("calculate_grand_total"); }, + cost_center: function(frm, cdt, cdn) { erpnext.utils.copy_value_in_all_rows(frm.doc, cdt, cdn, "expenses", "cost_center"); } diff --git a/erpnext/hr/doctype/expense_claim/expense_claim.json b/erpnext/hr/doctype/expense_claim/expense_claim.json index a268c15c70b..45b78bfb54e 100644 --- a/erpnext/hr/doctype/expense_claim/expense_claim.json +++ b/erpnext/hr/doctype/expense_claim/expense_claim.json @@ -379,11 +379,12 @@ "idx": 1, "is_submittable": 1, "links": [], - "modified": "2021-05-04 05:35:12.040199", + "modified": "2021-11-22 16:26:57.787838", "modified_by": "Administrator", "module": "HR", "name": "Expense Claim", "name_case": "Title Case", + "naming_rule": "By \"Naming Series\" field", "owner": "Administrator", "permissions": [ { diff --git a/erpnext/hr/doctype/expense_claim/expense_claim.py b/erpnext/hr/doctype/expense_claim/expense_claim.py index d785db7872c..7e3898b7d51 100644 --- a/erpnext/hr/doctype/expense_claim/expense_claim.py +++ b/erpnext/hr/doctype/expense_claim/expense_claim.py @@ -1,7 +1,6 @@ # Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors # License: GNU General Public License v3. See license.txt -from __future__ import unicode_literals import frappe from frappe import _ diff --git a/erpnext/hr/doctype/expense_claim/expense_claim_dashboard.py b/erpnext/hr/doctype/expense_claim/expense_claim_dashboard.py index a5682dc1e95..7539c7165d0 100644 --- a/erpnext/hr/doctype/expense_claim/expense_claim_dashboard.py +++ b/erpnext/hr/doctype/expense_claim/expense_claim_dashboard.py @@ -1,5 +1,3 @@ -from __future__ import unicode_literals - from frappe import _ diff --git a/erpnext/hr/doctype/expense_claim/test_expense_claim.py b/erpnext/hr/doctype/expense_claim/test_expense_claim.py index 9cb65f7e080..ec703614c82 100644 --- a/erpnext/hr/doctype/expense_claim/test_expense_claim.py +++ b/erpnext/hr/doctype/expense_claim/test_expense_claim.py @@ -1,6 +1,5 @@ # Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors and Contributors # See license.txt -from __future__ import unicode_literals import unittest @@ -176,7 +175,7 @@ def generate_taxes(): account = create_account(company=company_name, account_name="Output Tax CGST", account_type="Tax", parent_account=parent_account) return {'taxes':[{ "account_head": account, - "rate": 0, + "rate": 9, "description": "CGST", "tax_amount": 10, "total": 210 diff --git a/erpnext/hr/doctype/expense_claim_account/expense_claim_account.py b/erpnext/hr/doctype/expense_claim_account/expense_claim_account.py index a982002ebb4..0d46a226080 100644 --- a/erpnext/hr/doctype/expense_claim_account/expense_claim_account.py +++ b/erpnext/hr/doctype/expense_claim_account/expense_claim_account.py @@ -1,8 +1,6 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and contributors # For license information, please see license.txt -from __future__ import unicode_literals from frappe.model.document import Document diff --git a/erpnext/hr/doctype/expense_claim_advance/expense_claim_advance.json b/erpnext/hr/doctype/expense_claim_advance/expense_claim_advance.json index 45509257c11..aa479c83084 100644 --- a/erpnext/hr/doctype/expense_claim_advance/expense_claim_advance.json +++ b/erpnext/hr/doctype/expense_claim_advance/expense_claim_advance.json @@ -1,4 +1,5 @@ { + "actions": [], "creation": "2017-10-09 16:53:26.410762", "doctype": "DocType", "document_type": "Document", @@ -50,7 +51,7 @@ "fieldname": "unclaimed_amount", "fieldtype": "Currency", "in_list_view": 1, - "label": "Unclaimed amount", + "label": "Unclaimed Amount", "no_copy": 1, "oldfieldname": "advance_amount", "oldfieldtype": "Currency", @@ -65,7 +66,7 @@ "fieldname": "allocated_amount", "fieldtype": "Currency", "in_list_view": 1, - "label": "Allocated amount", + "label": "Allocated Amount", "no_copy": 1, "oldfieldname": "allocated_amount", "oldfieldtype": "Currency", @@ -87,7 +88,7 @@ ], "istable": 1, "links": [], - "modified": "2019-12-17 13:53:22.111766", + "modified": "2021-11-22 16:33:58.515819", "modified_by": "Administrator", "module": "HR", "name": "Expense Claim Advance", diff --git a/erpnext/hr/doctype/expense_claim_advance/expense_claim_advance.py b/erpnext/hr/doctype/expense_claim_advance/expense_claim_advance.py index 5607f41d917..68b2963f2bc 100644 --- a/erpnext/hr/doctype/expense_claim_advance/expense_claim_advance.py +++ b/erpnext/hr/doctype/expense_claim_advance/expense_claim_advance.py @@ -1,8 +1,6 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2017, Frappe Technologies Pvt. Ltd. and contributors # For license information, please see license.txt -from __future__ import unicode_literals from frappe.model.document import Document diff --git a/erpnext/hr/doctype/expense_claim_detail/__init__.py b/erpnext/hr/doctype/expense_claim_detail/__init__.py index baffc488252..e69de29bb2d 100644 --- a/erpnext/hr/doctype/expense_claim_detail/__init__.py +++ b/erpnext/hr/doctype/expense_claim_detail/__init__.py @@ -1 +0,0 @@ -from __future__ import unicode_literals diff --git a/erpnext/hr/doctype/expense_claim_detail/expense_claim_detail.py b/erpnext/hr/doctype/expense_claim_detail/expense_claim_detail.py index 019e9f4dfe2..f58f1287cbe 100644 --- a/erpnext/hr/doctype/expense_claim_detail/expense_claim_detail.py +++ b/erpnext/hr/doctype/expense_claim_detail/expense_claim_detail.py @@ -1,7 +1,6 @@ # Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors # License: GNU General Public License v3. See license.txt -from __future__ import unicode_literals from frappe.model.document import Document diff --git a/erpnext/hr/doctype/expense_claim_type/__init__.py b/erpnext/hr/doctype/expense_claim_type/__init__.py index baffc488252..e69de29bb2d 100644 --- a/erpnext/hr/doctype/expense_claim_type/__init__.py +++ b/erpnext/hr/doctype/expense_claim_type/__init__.py @@ -1 +0,0 @@ -from __future__ import unicode_literals diff --git a/erpnext/hr/doctype/expense_claim_type/expense_claim_type.py b/erpnext/hr/doctype/expense_claim_type/expense_claim_type.py index 101461c54b1..570b2c115fa 100644 --- a/erpnext/hr/doctype/expense_claim_type/expense_claim_type.py +++ b/erpnext/hr/doctype/expense_claim_type/expense_claim_type.py @@ -1,7 +1,6 @@ # Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors # License: GNU General Public License v3. See license.txt -from __future__ import unicode_literals import frappe from frappe import _ diff --git a/erpnext/hr/doctype/expense_claim_type/test_expense_claim_type.py b/erpnext/hr/doctype/expense_claim_type/test_expense_claim_type.py index f0c900e6ef0..a2403b6eb8f 100644 --- a/erpnext/hr/doctype/expense_claim_type/test_expense_claim_type.py +++ b/erpnext/hr/doctype/expense_claim_type/test_expense_claim_type.py @@ -1,7 +1,5 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors and Contributors # See license.txt -from __future__ import unicode_literals import unittest diff --git a/erpnext/hr/doctype/expense_taxes_and_charges/expense_taxes_and_charges.json b/erpnext/hr/doctype/expense_taxes_and_charges/expense_taxes_and_charges.json index 020457d4ec6..2f7b8fcf679 100644 --- a/erpnext/hr/doctype/expense_taxes_and_charges/expense_taxes_and_charges.json +++ b/erpnext/hr/doctype/expense_taxes_and_charges/expense_taxes_and_charges.json @@ -56,8 +56,6 @@ }, { "columns": 2, - "fetch_from": "account_head.tax_rate", - "fetch_if_empty": 1, "fieldname": "rate", "fieldtype": "Float", "in_list_view": 1, @@ -102,7 +100,7 @@ ], "istable": 1, "links": [], - "modified": "2020-09-23 20:27:36.027728", + "modified": "2021-10-26 20:27:36.027728", "modified_by": "Administrator", "module": "HR", "name": "Expense Taxes and Charges", @@ -111,4 +109,4 @@ "sort_field": "modified", "sort_order": "ASC", "track_changes": 1 -} \ No newline at end of file +} diff --git a/erpnext/hr/doctype/expense_taxes_and_charges/expense_taxes_and_charges.py b/erpnext/hr/doctype/expense_taxes_and_charges/expense_taxes_and_charges.py index 596e8c719a4..a28ef57b3fe 100644 --- a/erpnext/hr/doctype/expense_taxes_and_charges/expense_taxes_and_charges.py +++ b/erpnext/hr/doctype/expense_taxes_and_charges/expense_taxes_and_charges.py @@ -1,8 +1,6 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2019, Frappe Technologies Pvt. Ltd. and contributors # For license information, please see license.txt -from __future__ import unicode_literals # import frappe from frappe.model.document import Document diff --git a/erpnext/hr/doctype/holiday/__init__.py b/erpnext/hr/doctype/holiday/__init__.py index baffc488252..e69de29bb2d 100644 --- a/erpnext/hr/doctype/holiday/__init__.py +++ b/erpnext/hr/doctype/holiday/__init__.py @@ -1 +0,0 @@ -from __future__ import unicode_literals diff --git a/erpnext/hr/doctype/holiday/holiday.py b/erpnext/hr/doctype/holiday/holiday.py index fbfe7563aa2..85ca0b74fc7 100644 --- a/erpnext/hr/doctype/holiday/holiday.py +++ b/erpnext/hr/doctype/holiday/holiday.py @@ -1,7 +1,6 @@ # Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors # License: GNU General Public License v3. See license.txt -from __future__ import unicode_literals from frappe.model.document import Document diff --git a/erpnext/hr/doctype/holiday_list/__init__.py b/erpnext/hr/doctype/holiday_list/__init__.py index baffc488252..e69de29bb2d 100644 --- a/erpnext/hr/doctype/holiday_list/__init__.py +++ b/erpnext/hr/doctype/holiday_list/__init__.py @@ -1 +0,0 @@ -from __future__ import unicode_literals diff --git a/erpnext/hr/doctype/holiday_list/holiday_list.js b/erpnext/hr/doctype/holiday_list/holiday_list.js index 462bd8bb671..ea033c7ed92 100644 --- a/erpnext/hr/doctype/holiday_list/holiday_list.js +++ b/erpnext/hr/doctype/holiday_list/holiday_list.js @@ -1,10 +1,10 @@ // Copyright (c) 2016, Frappe Technologies Pvt. Ltd. and contributors // For license information, please see license.txt -frappe.ui.form.on('Holiday List', { +frappe.ui.form.on("Holiday List", { refresh: function(frm) { if (frm.doc.holidays) { - frm.set_value('total_holidays', frm.doc.holidays.length); + frm.set_value("total_holidays", frm.doc.holidays.length); } }, from_date: function(frm) { @@ -14,3 +14,36 @@ frappe.ui.form.on('Holiday List', { } } }); + +frappe.tour["Holiday List"] = [ + { + fieldname: "holiday_list_name", + title: "Holiday List Name", + description: __("Enter a name for this Holiday List."), + }, + { + fieldname: "from_date", + title: "From Date", + description: __("Based on your HR Policy, select your leave allocation period's start date"), + }, + { + fieldname: "to_date", + title: "To Date", + description: __("Based on your HR Policy, select your leave allocation period's end date"), + }, + { + fieldname: "weekly_off", + title: "Weekly Off", + description: __("Select your weekly off day"), + }, + { + fieldname: "get_weekly_off_dates", + title: "Add Holidays", + description: __("Click on Add to Holidays. This will populate the holidays table with all the dates that fall on the selected weekly off. Repeat the process for populating the dates for all your weekly holidays"), + }, + { + fieldname: "holidays", + title: "Holidays", + description: __("Here, your weekly offs are pre-populated based on the previous selections. You can add more rows to also add public and national holidays individually.") + }, +]; diff --git a/erpnext/hr/doctype/holiday_list/holiday_list.py b/erpnext/hr/doctype/holiday_list/holiday_list.py index f46f14d8416..a8c8c16d0d2 100644 --- a/erpnext/hr/doctype/holiday_list/holiday_list.py +++ b/erpnext/hr/doctype/holiday_list/holiday_list.py @@ -1,8 +1,6 @@ - # Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors # License: GNU General Public License v3. See license.txt -from __future__ import unicode_literals import json @@ -94,9 +92,11 @@ def get_events(start, end, filters=None): update={"allDay": 1}) -def is_holiday(holiday_list, date=today()): +def is_holiday(holiday_list, date=None): """Returns true if the given date is a holiday in the given holiday list """ + if date is None: + date = today() if holiday_list: return bool(frappe.get_all('Holiday List', dict(name=holiday_list, holiday_date=date))) diff --git a/erpnext/hr/doctype/holiday_list/holiday_list_dashboard.py b/erpnext/hr/doctype/holiday_list/holiday_list_dashboard.py index bbba36af875..4a540ce610d 100644 --- a/erpnext/hr/doctype/holiday_list/holiday_list_dashboard.py +++ b/erpnext/hr/doctype/holiday_list/holiday_list_dashboard.py @@ -1,6 +1,3 @@ -from __future__ import unicode_literals - - def get_data(): return { 'fieldname': 'holiday_list', diff --git a/erpnext/hr/doctype/holiday_list/test_holiday_list.py b/erpnext/hr/doctype/holiday_list/test_holiday_list.py index 27131932db4..c9239edb720 100644 --- a/erpnext/hr/doctype/holiday_list/test_holiday_list.py +++ b/erpnext/hr/doctype/holiday_list/test_holiday_list.py @@ -1,6 +1,5 @@ # Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors # License: GNU General Public License v3. See license.txt -from __future__ import unicode_literals import unittest from datetime import timedelta diff --git a/erpnext/hr/doctype/hr_settings/hr_settings.js b/erpnext/hr/doctype/hr_settings/hr_settings.js index ec99472d9bc..6e26a1fa71d 100644 --- a/erpnext/hr/doctype/hr_settings/hr_settings.js +++ b/erpnext/hr/doctype/hr_settings/hr_settings.js @@ -2,7 +2,22 @@ // For license information, please see license.txt frappe.ui.form.on('HR Settings', { - restrict_backdated_leave_application: function(frm) { - frm.toggle_reqd("role_allowed_to_create_backdated_leave_application", frm.doc.restrict_backdated_leave_application); - } }); + +frappe.tour['HR Settings'] = [ + { + fieldname: 'emp_created_by', + title: 'Employee Naming By', + description: __('Employee can be named by Employee ID if you assign one, or via Naming Series. Select your preference here.'), + }, + { + fieldname: 'standard_working_hours', + title: 'Standard Working Hours', + description: __('Enter the Standard Working Hours for a normal work day. These hours will be used in calculations of reports such as Employee Hours Utilization and Project Profitability analysis.'), + }, + { + fieldname: 'leave_and_expense_claim_settings', + title: 'Leave and Expense Clain Settings', + description: __('Review various other settings related to Employee Leaves and Expense Claim') + } +]; diff --git a/erpnext/hr/doctype/hr_settings/hr_settings.json b/erpnext/hr/doctype/hr_settings/hr_settings.json index 8aa3c0ca9f1..5148435c130 100644 --- a/erpnext/hr/doctype/hr_settings/hr_settings.json +++ b/erpnext/hr/doctype/hr_settings/hr_settings.json @@ -7,30 +7,36 @@ "engine": "InnoDB", "field_order": [ "employee_settings", - "retirement_age", "emp_created_by", - "column_break_4", "standard_working_hours", - "expense_approver_mandatory_in_expense_claim", + "column_break_9", + "retirement_age", "reminders_section", "send_birthday_reminders", - "column_break_9", - "send_work_anniversary_reminders", "column_break_11", + "send_work_anniversary_reminders", + "column_break_18", "send_holiday_reminders", "frequency", - "leave_settings", + "leave_and_expense_claim_settings", "send_leave_notification", "leave_approval_notification_template", "leave_status_notification_template", - "role_allowed_to_create_backdated_leave_application", - "column_break_18", "leave_approver_mandatory_in_leave_application", + "restrict_backdated_leave_application", + "role_allowed_to_create_backdated_leave_application", + "column_break_29", + "expense_approver_mandatory_in_expense_claim", "show_leaves_of_all_department_members_in_calendar", "auto_leave_encashment", - "restrict_backdated_leave_application", - "hiring_settings", - "check_vacancies" + "hiring_settings_section", + "check_vacancies", + "send_interview_reminder", + "interview_reminder_template", + "remind_before", + "column_break_4", + "send_interview_feedback_reminder", + "feedback_reminder_notification_template" ], "fields": [ { @@ -39,17 +45,16 @@ "label": "Employee Settings" }, { - "description": "Enter retirement age in years", "fieldname": "retirement_age", "fieldtype": "Data", - "label": "Retirement Age" + "label": "Retirement Age (In Years)" }, { "default": "Naming Series", - "description": "Employee records are created using the selected field", + "description": "Employee records are created using the selected option", "fieldname": "emp_created_by", "fieldtype": "Select", - "label": "Employee Records to be created by", + "label": "Employee Naming By", "options": "Naming Series\nEmployee Number\nFull Name" }, { @@ -62,28 +67,6 @@ "fieldtype": "Check", "label": "Expense Approver Mandatory In Expense Claim" }, - { - "collapsible": 1, - "fieldname": "leave_settings", - "fieldtype": "Section Break", - "label": "Leave Settings" - }, - { - "depends_on": "eval: doc.send_leave_notification == 1", - "fieldname": "leave_approval_notification_template", - "fieldtype": "Link", - "label": "Leave Approval Notification Template", - "mandatory_depends_on": "eval: doc.send_leave_notification == 1", - "options": "Email Template" - }, - { - "depends_on": "eval: doc.send_leave_notification == 1", - "fieldname": "leave_status_notification_template", - "fieldtype": "Link", - "label": "Leave Status Notification Template", - "mandatory_depends_on": "eval: doc.send_leave_notification == 1", - "options": "Email Template" - }, { "fieldname": "column_break_18", "fieldtype": "Column Break" @@ -100,35 +83,18 @@ "fieldtype": "Check", "label": "Show Leaves Of All Department Members In Calendar" }, - { - "collapsible": 1, - "fieldname": "hiring_settings", - "fieldtype": "Section Break", - "label": "Hiring Settings" - }, - { - "default": "0", - "fieldname": "check_vacancies", - "fieldtype": "Check", - "label": "Check Vacancies On Job Offer Creation" - }, { "default": "0", "fieldname": "auto_leave_encashment", "fieldtype": "Check", "label": "Auto Leave Encashment" }, - { - "default": "0", - "fieldname": "restrict_backdated_leave_application", - "fieldtype": "Check", - "label": "Restrict Backdated Leave Application" - }, { "depends_on": "eval:doc.restrict_backdated_leave_application == 1", "fieldname": "role_allowed_to_create_backdated_leave_application", "fieldtype": "Link", "label": "Role Allowed to Create Backdated Leave Application", + "mandatory_depends_on": "eval:doc.restrict_backdated_leave_application == 1", "options": "Role" }, { @@ -137,11 +103,40 @@ "fieldtype": "Check", "label": "Send Leave Notification" }, + { + "depends_on": "eval: doc.send_leave_notification == 1", + "fieldname": "leave_approval_notification_template", + "fieldtype": "Link", + "label": "Leave Approval Notification Template", + "mandatory_depends_on": "eval: doc.send_leave_notification == 1", + "options": "Email Template" + }, + { + "depends_on": "eval: doc.send_leave_notification == 1", + "fieldname": "leave_status_notification_template", + "fieldtype": "Link", + "label": "Leave Status Notification Template", + "mandatory_depends_on": "eval: doc.send_leave_notification == 1", + "options": "Email Template" + }, { "fieldname": "standard_working_hours", "fieldtype": "Int", "label": "Standard Working Hours" }, + { + "collapsible": 1, + "fieldname": "leave_and_expense_claim_settings", + "fieldtype": "Section Break", + "label": "Leave and Expense Claim Settings" + }, + { + "default": "00:15:00", + "depends_on": "send_interview_reminder", + "fieldname": "remind_before", + "fieldtype": "Time", + "label": "Remind Before" + }, { "collapsible": 1, "fieldname": "reminders_section", @@ -166,6 +161,7 @@ "fieldname": "frequency", "fieldtype": "Select", "label": "Set the frequency for holiday reminders", + "mandatory_depends_on": "send_holiday_reminders", "options": "Weekly\nMonthly" }, { @@ -181,13 +177,62 @@ { "fieldname": "column_break_11", "fieldtype": "Column Break" + }, + { + "default": "0", + "fieldname": "send_interview_reminder", + "fieldtype": "Check", + "label": "Send Interview Reminder" + }, + { + "default": "0", + "fieldname": "send_interview_feedback_reminder", + "fieldtype": "Check", + "label": "Send Interview Feedback Reminder" + }, + { + "fieldname": "column_break_29", + "fieldtype": "Column Break" + }, + { + "depends_on": "send_interview_feedback_reminder", + "fieldname": "feedback_reminder_notification_template", + "fieldtype": "Link", + "label": "Feedback Reminder Notification Template", + "mandatory_depends_on": "send_interview_feedback_reminder", + "options": "Email Template" + }, + { + "depends_on": "send_interview_reminder", + "fieldname": "interview_reminder_template", + "fieldtype": "Link", + "label": "Interview Reminder Notification Template", + "mandatory_depends_on": "send_interview_reminder", + "options": "Email Template" + }, + { + "default": "0", + "fieldname": "restrict_backdated_leave_application", + "fieldtype": "Check", + "label": "Restrict Backdated Leave Application" + }, + { + "fieldname": "hiring_settings_section", + "fieldtype": "Section Break", + "label": "Hiring Settings" + }, + { + "default": "0", + "fieldname": "check_vacancies", + "fieldtype": "Check", + "label": "Check Vacancies On Job Offer Creation" } ], "icon": "fa fa-cog", "idx": 1, "issingle": 1, "links": [], - "modified": "2021-08-24 14:54:12.834162", + "modified": "2021-10-01 23:46:11.098236", "modified_by": "Administrator", "module": "HR", "name": "HR Settings", diff --git a/erpnext/hr/doctype/hr_settings/test_hr_settings.py b/erpnext/hr/doctype/hr_settings/test_hr_settings.py index 69a060a90f9..7e13213ff32 100644 --- a/erpnext/hr/doctype/hr_settings/test_hr_settings.py +++ b/erpnext/hr/doctype/hr_settings/test_hr_settings.py @@ -1,7 +1,5 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2018, Frappe Technologies Pvt. Ltd. and Contributors # See license.txt -from __future__ import unicode_literals import unittest diff --git a/erpnext/hr/doctype/identification_document_type/identification_document_type.py b/erpnext/hr/doctype/identification_document_type/identification_document_type.py index 862cd374fb4..3bfcfaadcc8 100644 --- a/erpnext/hr/doctype/identification_document_type/identification_document_type.py +++ b/erpnext/hr/doctype/identification_document_type/identification_document_type.py @@ -1,8 +1,6 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2018, Frappe Technologies Pvt. Ltd. and contributors # For license information, please see license.txt -from __future__ import unicode_literals from frappe.model.document import Document diff --git a/erpnext/hr/doctype/identification_document_type/test_identification_document_type.py b/erpnext/hr/doctype/identification_document_type/test_identification_document_type.py index 87f302450db..3e8f7ab0d6d 100644 --- a/erpnext/hr/doctype/identification_document_type/test_identification_document_type.py +++ b/erpnext/hr/doctype/identification_document_type/test_identification_document_type.py @@ -1,7 +1,5 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2018, Frappe Technologies Pvt. Ltd. and Contributors # See license.txt -from __future__ import unicode_literals import unittest diff --git a/erpnext/hr/doctype/interest/interest.py b/erpnext/hr/doctype/interest/interest.py index 1b8f49f9585..3563f7f3a0a 100644 --- a/erpnext/hr/doctype/interest/interest.py +++ b/erpnext/hr/doctype/interest/interest.py @@ -1,8 +1,6 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and contributors # For license information, please see license.txt -from __future__ import unicode_literals from frappe.model.document import Document diff --git a/erpnext/hr/doctype/interest/test_interest.py b/erpnext/hr/doctype/interest/test_interest.py index f3727bee0b0..d4ecd9b841e 100644 --- a/erpnext/hr/doctype/interest/test_interest.py +++ b/erpnext/hr/doctype/interest/test_interest.py @@ -1,7 +1,5 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors # See license.txt -from __future__ import unicode_literals import unittest diff --git a/erpnext/healthcare/doctype/clinical_procedure_template/__init__.py b/erpnext/hr/doctype/interview/__init__.py similarity index 100% rename from erpnext/healthcare/doctype/clinical_procedure_template/__init__.py rename to erpnext/hr/doctype/interview/__init__.py diff --git a/erpnext/hr/doctype/interview/interview.js b/erpnext/hr/doctype/interview/interview.js new file mode 100644 index 00000000000..6341e3a62b4 --- /dev/null +++ b/erpnext/hr/doctype/interview/interview.js @@ -0,0 +1,237 @@ +// Copyright (c) 2021, Frappe Technologies Pvt. Ltd. and contributors +// For license information, please see license.txt + +frappe.ui.form.on('Interview', { + onload: function (frm) { + frm.events.set_job_applicant_query(frm); + + frm.set_query('interviewer', 'interview_details', function () { + return { + query: 'erpnext.hr.doctype.interview.interview.get_interviewer_list' + }; + }); + }, + + refresh: function (frm) { + if (frm.doc.docstatus != 2 && !frm.doc.__islocal) { + if (frm.doc.status === 'Pending') { + frm.add_custom_button(__('Reschedule Interview'), function() { + frm.events.show_reschedule_dialog(frm); + frm.refresh(); + }); + } + + let allowed_interviewers = []; + frm.doc.interview_details.forEach(values => { + allowed_interviewers.push(values.interviewer); + }); + + if ((allowed_interviewers.includes(frappe.session.user))) { + frappe.db.get_value('Interview Feedback', {'interviewer': frappe.session.user, 'interview': frm.doc.name, 'docstatus': 1}, 'name', (r) => { + if (Object.keys(r).length === 0) { + frm.add_custom_button(__('Submit Feedback'), function () { + frappe.call({ + method: 'erpnext.hr.doctype.interview.interview.get_expected_skill_set', + args: { + interview_round: frm.doc.interview_round + }, + callback: function (r) { + frm.events.show_feedback_dialog(frm, r.message); + frm.refresh(); + } + }); + }).addClass('btn-primary'); + } + }); + } + } + }, + + show_reschedule_dialog: function (frm) { + let d = new frappe.ui.Dialog({ + title: 'Reschedule Interview', + fields: [ + { + label: 'Schedule On', + fieldname: 'scheduled_on', + fieldtype: 'Date', + reqd: 1 + }, + { + label: 'From Time', + fieldname: 'from_time', + fieldtype: 'Time', + reqd: 1 + }, + { + label: 'To Time', + fieldname: 'to_time', + fieldtype: 'Time', + reqd: 1 + } + ], + primary_action_label: 'Reschedule', + primary_action(values) { + frm.call({ + method: 'reschedule_interview', + doc: frm.doc, + args: { + scheduled_on: values.scheduled_on, + from_time: values.from_time, + to_time: values.to_time + } + }).then(() => { + frm.refresh(); + d.hide(); + }); + } + }); + d.show(); + }, + + show_feedback_dialog: function (frm, data) { + let fields = frm.events.get_fields_for_feedback(); + + let d = new frappe.ui.Dialog({ + title: __('Submit Feedback'), + fields: [ + { + fieldname: 'skill_set', + fieldtype: 'Table', + label: __('Skill Assessment'), + cannot_add_rows: false, + in_editable_grid: true, + reqd: 1, + fields: fields, + data: data + }, + { + fieldname: 'result', + fieldtype: 'Select', + options: ['', 'Cleared', 'Rejected'], + label: __('Result') + }, + { + fieldname: 'feedback', + fieldtype: 'Small Text', + label: __('Feedback') + } + ], + size: 'large', + minimizable: true, + primary_action: function(values) { + frappe.call({ + method: 'erpnext.hr.doctype.interview.interview.create_interview_feedback', + args: { + data: values, + interview_name: frm.doc.name, + interviewer: frappe.session.user, + job_applicant: frm.doc.job_applicant + } + }).then(() => { + frm.refresh(); + }); + d.hide(); + } + }); + d.show(); + }, + + get_fields_for_feedback: function () { + return [{ + fieldtype: 'Link', + fieldname: 'skill', + options: 'Skill', + in_list_view: 1, + label: __('Skill') + }, { + fieldtype: 'Rating', + fieldname: 'rating', + label: __('Rating'), + in_list_view: 1, + reqd: 1, + }]; + }, + + set_job_applicant_query: function (frm) { + frm.set_query('job_applicant', function () { + let job_applicant_filters = { + status: ['!=', 'Rejected'] + }; + if (frm.doc.designation) { + job_applicant_filters.designation = frm.doc.designation; + } + return { + filters: job_applicant_filters + }; + }); + }, + + interview_round: async function (frm) { + frm.events.reset_values(frm); + frm.set_value('job_applicant', ''); + + let round_data = (await frappe.db.get_value('Interview Round', frm.doc.interview_round, 'designation')).message; + frm.set_value('designation', round_data.designation); + frm.events.set_job_applicant_query(frm); + + if (frm.doc.interview_round) { + frm.events.set_interview_details(frm); + } else { + frm.set_value('interview_details', []); + } + }, + + set_interview_details: function (frm) { + frappe.call({ + method: 'erpnext.hr.doctype.interview.interview.get_interviewers', + args: { + interview_round: frm.doc.interview_round + }, + callback: function (data) { + let interview_details = data.message; + frm.set_value('interview_details', []); + if (data.message.length) { + frm.set_value('interview_details', interview_details); + } + } + }); + }, + + job_applicant: function (frm) { + if (!frm.doc.interview_round) { + frm.doc.job_applicant = ''; + frm.refresh(); + frappe.throw(__('Select Interview Round First')); + } + + if (frm.doc.job_applicant) { + frm.events.set_designation_and_job_opening(frm); + } else { + frm.events.reset_values(frm); + } + }, + + set_designation_and_job_opening: async function (frm) { + let round_data = (await frappe.db.get_value('Interview Round', frm.doc.interview_round, 'designation')).message; + frm.set_value('designation', round_data.designation); + frm.events.set_job_applicant_query(frm); + + let job_applicant_data = (await frappe.db.get_value( + 'Job Applicant', frm.doc.job_applicant, ['designation', 'job_title', 'resume_link'], + )).message; + + if (!round_data.designation) { + frm.set_value('designation', job_applicant_data.designation); + } + + frm.set_value('job_opening', job_applicant_data.job_title); + frm.set_value('resume_link', job_applicant_data.resume_link); + }, + + reset_values: function (frm) { + frm.set_value('designation', ''); + frm.set_value('job_opening', ''); + frm.set_value('resume_link', ''); + } +}); diff --git a/erpnext/hr/doctype/interview/interview.json b/erpnext/hr/doctype/interview/interview.json new file mode 100644 index 00000000000..0d393e7556f --- /dev/null +++ b/erpnext/hr/doctype/interview/interview.json @@ -0,0 +1,254 @@ +{ + "actions": [], + "autoname": "HR-INT-.YYYY.-.####", + "creation": "2021-04-12 15:03:11.524090", + "doctype": "DocType", + "editable_grid": 1, + "engine": "InnoDB", + "field_order": [ + "interview_details_section", + "interview_round", + "job_applicant", + "job_opening", + "designation", + "resume_link", + "column_break_4", + "status", + "scheduled_on", + "from_time", + "to_time", + "interview_feedback_section", + "interview_details", + "ratings_section", + "expected_average_rating", + "column_break_12", + "average_rating", + "section_break_13", + "interview_summary", + "reminded", + "amended_from" + ], + "fields": [ + { + "fieldname": "job_applicant", + "fieldtype": "Link", + "in_list_view": 1, + "in_standard_filter": 1, + "label": "Job Applicant", + "options": "Job Applicant", + "reqd": 1 + }, + { + "fieldname": "job_opening", + "fieldtype": "Link", + "label": "Job Opening", + "options": "Job Opening", + "read_only": 1 + }, + { + "fieldname": "interview_round", + "fieldtype": "Link", + "in_list_view": 1, + "in_standard_filter": 1, + "label": "Interview Round", + "options": "Interview Round", + "reqd": 1 + }, + { + "default": "Pending", + "fieldname": "status", + "fieldtype": "Select", + "in_list_view": 1, + "in_standard_filter": 1, + "label": "Status", + "options": "Pending\nUnder Review\nCleared\nRejected", + "reqd": 1 + }, + { + "fieldname": "ratings_section", + "fieldtype": "Section Break", + "label": "Ratings" + }, + { + "allow_on_submit": 1, + "fieldname": "average_rating", + "fieldtype": "Rating", + "in_list_view": 1, + "label": "Obtained Average Rating", + "read_only": 1 + }, + { + "allow_on_submit": 1, + "fieldname": "interview_summary", + "fieldtype": "Text" + }, + { + "fieldname": "column_break_4", + "fieldtype": "Column Break" + }, + { + "fieldname": "resume_link", + "fieldtype": "Data", + "label": "Resume link" + }, + { + "fieldname": "interview_details_section", + "fieldtype": "Section Break", + "label": "Details" + }, + { + "fetch_from": "interview_round.expected_average_rating", + "fieldname": "expected_average_rating", + "fieldtype": "Rating", + "label": "Expected Average Rating", + "read_only": 1 + }, + { + "collapsible": 1, + "fieldname": "section_break_13", + "fieldtype": "Section Break", + "label": "Interview Summary" + }, + { + "fieldname": "column_break_12", + "fieldtype": "Column Break" + }, + { + "fetch_from": "interview_round.designation", + "fieldname": "designation", + "fieldtype": "Link", + "in_list_view": 1, + "in_standard_filter": 1, + "label": "Designation", + "options": "Designation", + "read_only": 1 + }, + { + "fieldname": "amended_from", + "fieldtype": "Link", + "label": "Amended From", + "no_copy": 1, + "options": "Interview", + "print_hide": 1, + "read_only": 1 + }, + { + "fieldname": "scheduled_on", + "fieldtype": "Date", + "in_list_view": 1, + "in_standard_filter": 1, + "label": "Scheduled On", + "reqd": 1, + "set_only_once": 1 + }, + { + "default": "0", + "fieldname": "reminded", + "fieldtype": "Check", + "hidden": 1, + "label": "Reminded" + }, + { + "allow_on_submit": 1, + "fieldname": "interview_details", + "fieldtype": "Table", + "options": "Interview Detail" + }, + { + "fieldname": "interview_feedback_section", + "fieldtype": "Section Break", + "label": "Feedback" + }, + { + "fieldname": "from_time", + "fieldtype": "Time", + "in_list_view": 1, + "label": "From Time", + "reqd": 1, + "set_only_once": 1 + }, + { + "fieldname": "to_time", + "fieldtype": "Time", + "in_list_view": 1, + "label": "To Time", + "reqd": 1, + "set_only_once": 1 + } + ], + "index_web_pages_for_search": 1, + "is_submittable": 1, + "links": [ + { + "link_doctype": "Interview Feedback", + "link_fieldname": "interview" + } + ], + "modified": "2021-09-30 13:30:05.421035", + "modified_by": "Administrator", + "module": "HR", + "name": "Interview", + "owner": "Administrator", + "permissions": [ + { + "cancel": 1, + "create": 1, + "delete": 1, + "email": 1, + "export": 1, + "print": 1, + "read": 1, + "report": 1, + "role": "System Manager", + "share": 1, + "submit": 1, + "write": 1 + }, + { + "cancel": 1, + "create": 1, + "delete": 1, + "email": 1, + "export": 1, + "print": 1, + "read": 1, + "report": 1, + "role": "HR Manager", + "share": 1, + "submit": 1, + "write": 1 + }, + { + "cancel": 1, + "create": 1, + "delete": 1, + "email": 1, + "export": 1, + "print": 1, + "read": 1, + "report": 1, + "role": "Interviewer", + "share": 1, + "submit": 1, + "write": 1 + }, + { + "cancel": 1, + "create": 1, + "delete": 1, + "email": 1, + "export": 1, + "print": 1, + "read": 1, + "report": 1, + "role": "HR User", + "share": 1, + "submit": 1, + "write": 1 + } + ], + "sort_field": "modified", + "sort_order": "DESC", + "title_field": "job_applicant", + "track_changes": 1 +} \ No newline at end of file diff --git a/erpnext/hr/doctype/interview/interview.py b/erpnext/hr/doctype/interview/interview.py new file mode 100644 index 00000000000..4bb003ded18 --- /dev/null +++ b/erpnext/hr/doctype/interview/interview.py @@ -0,0 +1,290 @@ +# Copyright (c) 2021, Frappe Technologies Pvt. Ltd. and contributors +# For license information, please see license.txt + + +import datetime + +import frappe +from frappe import _ +from frappe.model.document import Document +from frappe.utils import cstr, get_datetime, get_link_to_form + + +class DuplicateInterviewRoundError(frappe.ValidationError): + pass + +class Interview(Document): + def validate(self): + self.validate_duplicate_interview() + self.validate_designation() + self.validate_overlap() + + def on_submit(self): + if self.status not in ['Cleared', 'Rejected']: + frappe.throw(_('Only Interviews with Cleared or Rejected status can be submitted.'), title=_('Not Allowed')) + + def validate_duplicate_interview(self): + duplicate_interview = frappe.db.exists('Interview', { + 'job_applicant': self.job_applicant, + 'interview_round': self.interview_round, + 'docstatus': 1 + } + ) + + if duplicate_interview: + frappe.throw(_('Job Applicants are not allowed to appear twice for the same Interview round. Interview {0} already scheduled for Job Applicant {1}').format( + frappe.bold(get_link_to_form('Interview', duplicate_interview)), + frappe.bold(self.job_applicant) + )) + + def validate_designation(self): + applicant_designation = frappe.db.get_value('Job Applicant', self.job_applicant, 'designation') + if self.designation : + if self.designation != applicant_designation: + frappe.throw(_('Interview Round {0} is only for Designation {1}. Job Applicant has applied for the role {2}').format( + self.interview_round, frappe.bold(self.designation), applicant_designation), + exc=DuplicateInterviewRoundError) + else: + self.designation = applicant_designation + + def validate_overlap(self): + interviewers = [entry.interviewer for entry in self.interview_details] or [''] + + overlaps = frappe.db.sql(""" + SELECT interview.name + FROM `tabInterview` as interview + INNER JOIN `tabInterview Detail` as detail + WHERE + interview.scheduled_on = %s and interview.name != %s and interview.docstatus != 2 + and (interview.job_applicant = %s or detail.interviewer IN %s) and + ((from_time < %s and to_time > %s) or + (from_time > %s and to_time < %s) or + (from_time = %s)) + """, (self.scheduled_on, self.name, self.job_applicant, interviewers, + self.from_time, self.to_time, self.from_time, self.to_time, self.from_time)) + + if overlaps: + overlapping_details = _('Interview overlaps with {0}').format(get_link_to_form('Interview', overlaps[0][0])) + frappe.throw(overlapping_details, title=_('Overlap')) + + + @frappe.whitelist() + def reschedule_interview(self, scheduled_on, from_time, to_time): + original_date = self.scheduled_on + from_time = self.from_time + to_time = self.to_time + + self.db_set({ + 'scheduled_on': scheduled_on, + 'from_time': from_time, + 'to_time': to_time + }) + self.notify_update() + + recipients = get_recipients(self.name) + + try: + frappe.sendmail( + recipients= recipients, + subject=_('Interview: {0} Rescheduled').format(self.name), + message=_('Your Interview session is rescheduled from {0} {1} - {2} to {3} {4} - {5}').format( + original_date, from_time, to_time, self.scheduled_on, self.from_time, self.to_time), + reference_doctype=self.doctype, + reference_name=self.name + ) + except Exception: + frappe.msgprint(_('Failed to send the Interview Reschedule notification. Please configure your email account.')) + + frappe.msgprint(_('Interview Rescheduled successfully'), indicator='green') + + +def get_recipients(name, for_feedback=0): + interview = frappe.get_doc('Interview', name) + + if for_feedback: + recipients = [d.interviewer for d in interview.interview_details if not d.interview_feedback] + else: + recipients = [d.interviewer for d in interview.interview_details] + recipients.append(frappe.db.get_value('Job Applicant', interview.job_applicant, 'email_id')) + + return recipients + + +@frappe.whitelist() +def get_interviewers(interview_round): + return frappe.get_all('Interviewer', filters={'parent': interview_round}, fields=['user as interviewer']) + + +def send_interview_reminder(): + reminder_settings = frappe.db.get_value('HR Settings', 'HR Settings', + ['send_interview_reminder', 'interview_reminder_template'], as_dict=True) + + if not reminder_settings.send_interview_reminder: + return + + remind_before = cstr(frappe.db.get_single_value('HR Settings', 'remind_before')) or '01:00:00' + remind_before = datetime.datetime.strptime(remind_before, '%H:%M:%S') + reminder_date_time = datetime.datetime.now() + datetime.timedelta( + hours=remind_before.hour, minutes=remind_before.minute, seconds=remind_before.second) + + interviews = frappe.get_all('Interview', filters={ + 'scheduled_on': ['between', (datetime.datetime.now(), reminder_date_time)], + 'status': 'Pending', + 'reminded': 0, + 'docstatus': ['!=', 2] + }) + + interview_template = frappe.get_doc('Email Template', reminder_settings.interview_reminder_template) + + for d in interviews: + doc = frappe.get_doc('Interview', d.name) + context = doc.as_dict() + message = frappe.render_template(interview_template.response, context) + recipients = get_recipients(doc.name) + + frappe.sendmail( + recipients= recipients, + subject=interview_template.subject, + message=message, + reference_doctype=doc.doctype, + reference_name=doc.name + ) + + doc.db_set('reminded', 1) + + +def send_daily_feedback_reminder(): + reminder_settings = frappe.db.get_value('HR Settings', 'HR Settings', + ['send_interview_feedback_reminder', 'feedback_reminder_notification_template'], as_dict=True) + + if not reminder_settings.send_interview_feedback_reminder: + return + + interview_feedback_template = frappe.get_doc('Email Template', reminder_settings.feedback_reminder_notification_template) + interviews = frappe.get_all('Interview', filters={'status': ['in', ['Under Review', 'Pending']], 'docstatus': ['!=', 2]}) + + for entry in interviews: + recipients = get_recipients(entry.name, for_feedback=1) + + doc = frappe.get_doc('Interview', entry.name) + context = doc.as_dict() + + message = frappe.render_template(interview_feedback_template.response, context) + + if len(recipients): + frappe.sendmail( + recipients= recipients, + subject=interview_feedback_template.subject, + message=message, + reference_doctype='Interview', + reference_name=entry.name + ) + + +@frappe.whitelist() +def get_expected_skill_set(interview_round): + return frappe.get_all('Expected Skill Set', filters ={'parent': interview_round}, fields=['skill']) + + +@frappe.whitelist() +def create_interview_feedback(data, interview_name, interviewer, job_applicant): + import json + + + if isinstance(data, str): + data = frappe._dict(json.loads(data)) + + if frappe.session.user != interviewer: + frappe.throw(_('Only Interviewer Are allowed to submit Interview Feedback')) + + interview_feedback = frappe.new_doc('Interview Feedback') + interview_feedback.interview = interview_name + interview_feedback.interviewer = interviewer + interview_feedback.job_applicant = job_applicant + + for d in data.skill_set: + d = frappe._dict(d) + interview_feedback.append('skill_assessment', {'skill': d.skill, 'rating': d.rating}) + + interview_feedback.feedback = data.feedback + interview_feedback.result = data.result + + interview_feedback.save() + interview_feedback.submit() + + frappe.msgprint(_('Interview Feedback {0} submitted successfully').format( + get_link_to_form('Interview Feedback', interview_feedback.name))) + + +@frappe.whitelist() +@frappe.validate_and_sanitize_search_inputs +def get_interviewer_list(doctype, txt, searchfield, start, page_len, filters): + filters = [ + ['Has Role', 'parent', 'like', '%{}%'.format(txt)], + ['Has Role', 'role', '=', 'interviewer'], + ['Has Role', 'parenttype', '=', 'User'] + ] + + if filters and isinstance(filters, list): + filters.extend(filters) + + return frappe.get_all('Has Role', limit_start=start, limit_page_length=page_len, + filters=filters, fields = ['parent'], as_list=1) + + +@frappe.whitelist() +def get_events(start, end, filters=None): + """Returns events for Gantt / Calendar view rendering. + + :param start: Start date-time. + :param end: End date-time. + :param filters: Filters (JSON). + """ + from frappe.desk.calendar import get_event_conditions + + events = [] + + event_color = { + "Pending": "#fff4f0", + "Under Review": "#d3e8fc", + "Cleared": "#eaf5ed", + "Rejected": "#fce7e7" + } + + conditions = get_event_conditions('Interview', filters) + + interviews = frappe.db.sql(""" + SELECT DISTINCT + `tabInterview`.name, `tabInterview`.job_applicant, `tabInterview`.interview_round, + `tabInterview`.scheduled_on, `tabInterview`.status, `tabInterview`.from_time as from_time, + `tabInterview`.to_time as to_time + from + `tabInterview` + where + (`tabInterview`.scheduled_on between %(start)s and %(end)s) + and docstatus != 2 + {conditions} + """.format(conditions=conditions), { + "start": start, + "end": end + }, as_dict=True, update={"allDay": 0}) + + for d in interviews: + subject_data = [] + for field in ["name", "job_applicant", "interview_round"]: + if not d.get(field): + continue + subject_data.append(d.get(field)) + + color = event_color.get(d.status) + interview_data = { + 'from': get_datetime('%s %s' % (d.scheduled_on, d.from_time or '00:00:00')), + 'to': get_datetime('%s %s' % (d.scheduled_on, d.to_time or '00:00:00')), + 'name': d.name, + 'subject': '\n'.join(subject_data), + 'color': color if color else "#89bcde" + } + + events.append(interview_data) + + return events diff --git a/erpnext/hr/doctype/interview/interview_calendar.js b/erpnext/hr/doctype/interview/interview_calendar.js new file mode 100644 index 00000000000..b46b72ecb21 --- /dev/null +++ b/erpnext/hr/doctype/interview/interview_calendar.js @@ -0,0 +1,14 @@ + +frappe.views.calendar['Interview'] = { + field_map: { + 'start': 'from', + 'end': 'to', + 'id': 'name', + 'title': 'subject', + 'allDay': 'allDay', + 'color': 'color' + }, + order_by: 'scheduled_on', + gantt: true, + get_events_method: 'erpnext.hr.doctype.interview.interview.get_events' +}; diff --git a/erpnext/hr/doctype/interview/interview_feedback_reminder_template.html b/erpnext/hr/doctype/interview/interview_feedback_reminder_template.html new file mode 100644 index 00000000000..8d39fb54ef7 --- /dev/null +++ b/erpnext/hr/doctype/interview/interview_feedback_reminder_template.html @@ -0,0 +1,5 @@ +

Interview Feedback Reminder

+ +

+ Interview Feedback for Interview {{ name }} is not submitted yet. Please submit your feedback. Thank you, good day! +

diff --git a/erpnext/hr/doctype/interview/interview_list.js b/erpnext/hr/doctype/interview/interview_list.js new file mode 100644 index 00000000000..b1f072f0d4b --- /dev/null +++ b/erpnext/hr/doctype/interview/interview_list.js @@ -0,0 +1,12 @@ +frappe.listview_settings['Interview'] = { + has_indicator_for_draft: 1, + get_indicator: function(doc) { + let status_color = { + 'Pending': 'orange', + 'Under Review': 'blue', + 'Cleared': 'green', + 'Rejected': 'red', + }; + return [__(doc.status), status_color[doc.status], 'status,=,'+doc.status]; + } +}; diff --git a/erpnext/hr/doctype/interview/interview_reminder_notification_template.html b/erpnext/hr/doctype/interview/interview_reminder_notification_template.html new file mode 100644 index 00000000000..76de46e28db --- /dev/null +++ b/erpnext/hr/doctype/interview/interview_reminder_notification_template.html @@ -0,0 +1,5 @@ +

Interview Reminder

+ +

+ Interview: {{name}} is scheduled on {{scheduled_on}} from {{from_time}} to {{to_time}} +

diff --git a/erpnext/hr/doctype/interview/test_interview.py b/erpnext/hr/doctype/interview/test_interview.py new file mode 100644 index 00000000000..1a2257a6d90 --- /dev/null +++ b/erpnext/hr/doctype/interview/test_interview.py @@ -0,0 +1,172 @@ +# Copyright (c) 2021, Frappe Technologies Pvt. Ltd. and Contributors +# See license.txt + +import datetime +import os +import unittest + +import frappe +from frappe import _ +from frappe.core.doctype.user_permission.test_user_permission import create_user +from frappe.utils import add_days, getdate, nowtime + +from erpnext.hr.doctype.designation.test_designation import create_designation +from erpnext.hr.doctype.interview.interview import DuplicateInterviewRoundError +from erpnext.hr.doctype.job_applicant.test_job_applicant import create_job_applicant + + +class TestInterview(unittest.TestCase): + def test_validations_for_designation(self): + job_applicant = create_job_applicant() + interview = create_interview_and_dependencies(job_applicant.name, designation='_Test_Sales_manager', save=0) + self.assertRaises(DuplicateInterviewRoundError, interview.save) + + def test_notification_on_rescheduling(self): + job_applicant = create_job_applicant() + interview = create_interview_and_dependencies(job_applicant.name, scheduled_on=add_days(getdate(), -4)) + + previous_scheduled_date = interview.scheduled_on + frappe.db.sql("DELETE FROM `tabEmail Queue`") + + interview.reschedule_interview(add_days(getdate(previous_scheduled_date), 2), + from_time=nowtime(), to_time=nowtime()) + interview.reload() + + self.assertEqual(interview.scheduled_on, add_days(getdate(previous_scheduled_date), 2)) + + notification = frappe.get_all("Email Queue", filters={"message": ("like", "%Your Interview session is rescheduled from%")}) + self.assertIsNotNone(notification) + + def test_notification_for_scheduling(self): + from erpnext.hr.doctype.interview.interview import send_interview_reminder + + setup_reminder_settings() + + job_applicant = create_job_applicant() + scheduled_on = datetime.datetime.now() + datetime.timedelta(minutes=10) + + interview = create_interview_and_dependencies(job_applicant.name, scheduled_on=scheduled_on) + + frappe.db.sql("DELETE FROM `tabEmail Queue`") + send_interview_reminder() + + interview.reload() + + email_queue = frappe.db.sql("""select * from `tabEmail Queue`""", as_dict=True) + self.assertTrue("Subject: Interview Reminder" in email_queue[0].message) + + def test_notification_for_feedback_submission(self): + from erpnext.hr.doctype.interview.interview import send_daily_feedback_reminder + + setup_reminder_settings() + + job_applicant = create_job_applicant() + scheduled_on = add_days(getdate(), -4) + create_interview_and_dependencies(job_applicant.name, scheduled_on=scheduled_on) + + frappe.db.sql("DELETE FROM `tabEmail Queue`") + send_daily_feedback_reminder() + + email_queue = frappe.db.sql("""select * from `tabEmail Queue`""", as_dict=True) + self.assertTrue("Subject: Interview Feedback Reminder" in email_queue[0].message) + + def tearDown(self): + frappe.db.rollback() + + +def create_interview_and_dependencies(job_applicant, scheduled_on=None, from_time=None, to_time=None, designation=None, save=1): + if designation: + designation=create_designation(designation_name = "_Test_Sales_manager").name + + interviewer_1 = create_user("test_interviewer1@example.com", "Interviewer") + interviewer_2 = create_user("test_interviewer2@example.com", "Interviewer") + + interview_round = create_interview_round( + "Technical Round", ["Python", "JS"], + designation=designation, save=True + ) + + interview = frappe.new_doc("Interview") + interview.interview_round = interview_round.name + interview.job_applicant = job_applicant + interview.scheduled_on = scheduled_on or getdate() + interview.from_time = from_time or nowtime() + interview.to_time = to_time or nowtime() + + interview.append("interview_details", {"interviewer": interviewer_1.name}) + interview.append("interview_details", {"interviewer": interviewer_2.name}) + + if save: + interview.save() + + return interview + +def create_interview_round(name, skill_set, interviewers=[], designation=None, save=True): + create_skill_set(skill_set) + interview_round = frappe.new_doc("Interview Round") + interview_round.round_name = name + interview_round.interview_type = create_interview_type() + interview_round.expected_average_rating = 4 + if designation: + interview_round.designation = designation + + for skill in skill_set: + interview_round.append("expected_skill_set", {"skill": skill}) + + for interviewer in interviewers: + interview_round.append("interviewer", { + "user": interviewer + }) + + if save: + interview_round.save() + + return interview_round + +def create_skill_set(skill_set): + for skill in skill_set: + if not frappe.db.exists("Skill", skill): + doc = frappe.new_doc("Skill") + doc.skill_name = skill + doc.save() + +def create_interview_type(name="test_interview_type"): + if frappe.db.exists("Interview Type", name): + return frappe.get_doc("Interview Type", name).name + else: + doc = frappe.new_doc("Interview Type") + doc.name = name + doc.description = "_Test_Description" + doc.save() + + return doc.name + +def setup_reminder_settings(): + if not frappe.db.exists('Email Template', _('Interview Reminder')): + base_path = frappe.get_app_path('erpnext', 'hr', 'doctype') + response = frappe.read_file(os.path.join(base_path, 'interview/interview_reminder_notification_template.html')) + + frappe.get_doc({ + 'doctype': 'Email Template', + 'name': _('Interview Reminder'), + 'response': response, + 'subject': _('Interview Reminder'), + 'owner': frappe.session.user, + }).insert(ignore_permissions=True) + + if not frappe.db.exists('Email Template', _('Interview Feedback Reminder')): + base_path = frappe.get_app_path('erpnext', 'hr', 'doctype') + response = frappe.read_file(os.path.join(base_path, 'interview/interview_feedback_reminder_template.html')) + + frappe.get_doc({ + 'doctype': 'Email Template', + 'name': _('Interview Feedback Reminder'), + 'response': response, + 'subject': _('Interview Feedback Reminder'), + 'owner': frappe.session.user, + }).insert(ignore_permissions=True) + + hr_settings = frappe.get_doc('HR Settings') + hr_settings.interview_reminder_template = _('Interview Reminder') + hr_settings.feedback_reminder_notification_template = _('Interview Feedback Reminder') + hr_settings.save() diff --git a/erpnext/healthcare/doctype/codification_table/__init__.py b/erpnext/hr/doctype/interview_detail/__init__.py similarity index 100% rename from erpnext/healthcare/doctype/codification_table/__init__.py rename to erpnext/hr/doctype/interview_detail/__init__.py diff --git a/erpnext/hr/doctype/interview_detail/interview_detail.js b/erpnext/hr/doctype/interview_detail/interview_detail.js new file mode 100644 index 00000000000..88518ca4cc1 --- /dev/null +++ b/erpnext/hr/doctype/interview_detail/interview_detail.js @@ -0,0 +1,8 @@ +// Copyright (c) 2021, Frappe Technologies Pvt. Ltd. and contributors +// For license information, please see license.txt + +frappe.ui.form.on('Interview Detail', { + // refresh: function(frm) { + + // } +}); diff --git a/erpnext/hr/doctype/interview_detail/interview_detail.json b/erpnext/hr/doctype/interview_detail/interview_detail.json new file mode 100644 index 00000000000..b5b49c0993a --- /dev/null +++ b/erpnext/hr/doctype/interview_detail/interview_detail.json @@ -0,0 +1,74 @@ +{ + "actions": [], + "creation": "2021-04-12 16:24:10.382863", + "doctype": "DocType", + "editable_grid": 1, + "engine": "InnoDB", + "field_order": [ + "interviewer", + "interview_feedback", + "average_rating", + "result", + "column_break_4", + "comments" + ], + "fields": [ + { + "fieldname": "interviewer", + "fieldtype": "Link", + "in_list_view": 1, + "label": "Interviewer", + "options": "User" + }, + { + "allow_on_submit": 1, + "fieldname": "interview_feedback", + "fieldtype": "Link", + "in_list_view": 1, + "label": "Interview Feedback", + "options": "Interview Feedback", + "read_only": 1 + }, + { + "allow_on_submit": 1, + "fieldname": "average_rating", + "fieldtype": "Rating", + "in_list_view": 1, + "label": "Average Rating", + "read_only": 1 + }, + { + "fieldname": "column_break_4", + "fieldtype": "Column Break" + }, + { + "allow_on_submit": 1, + "fetch_from": "interview_feedback.feedback", + "fieldname": "comments", + "fieldtype": "Text", + "label": "Comments", + "read_only": 1 + }, + { + "allow_on_submit": 1, + "fieldname": "result", + "fieldtype": "Select", + "in_list_view": 1, + "label": "Result", + "options": "\nCleared\nRejected", + "read_only": 1 + } + ], + "index_web_pages_for_search": 1, + "istable": 1, + "links": [], + "modified": "2021-09-29 13:13:25.865063", + "modified_by": "Administrator", + "module": "HR", + "name": "Interview Detail", + "owner": "Administrator", + "permissions": [], + "sort_field": "modified", + "sort_order": "DESC", + "track_changes": 1 +} \ No newline at end of file diff --git a/erpnext/hr/doctype/interview_detail/interview_detail.py b/erpnext/hr/doctype/interview_detail/interview_detail.py new file mode 100644 index 00000000000..d44e29a9c1d --- /dev/null +++ b/erpnext/hr/doctype/interview_detail/interview_detail.py @@ -0,0 +1,10 @@ +# Copyright (c) 2021, Frappe Technologies Pvt. Ltd. and contributors +# For license information, please see license.txt + + +# import frappe +from frappe.model.document import Document + + +class InterviewDetail(Document): + pass diff --git a/erpnext/buying/doctype/supplier_item_group/test_supplier_item_group.py b/erpnext/hr/doctype/interview_detail/test_interview_detail.py similarity index 53% rename from erpnext/buying/doctype/supplier_item_group/test_supplier_item_group.py rename to erpnext/hr/doctype/interview_detail/test_interview_detail.py index 55ba85ef2d6..68a1f724851 100644 --- a/erpnext/buying/doctype/supplier_item_group/test_supplier_item_group.py +++ b/erpnext/hr/doctype/interview_detail/test_interview_detail.py @@ -1,11 +1,9 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2021, Frappe Technologies Pvt. Ltd. and Contributors # See license.txt -from __future__ import unicode_literals # import frappe import unittest -class TestSupplierItemGroup(unittest.TestCase): +class TestInterviewDetail(unittest.TestCase): pass diff --git a/erpnext/healthcare/doctype/complaint/__init__.py b/erpnext/hr/doctype/interview_feedback/__init__.py similarity index 100% rename from erpnext/healthcare/doctype/complaint/__init__.py rename to erpnext/hr/doctype/interview_feedback/__init__.py diff --git a/erpnext/hr/doctype/interview_feedback/interview_feedback.js b/erpnext/hr/doctype/interview_feedback/interview_feedback.js new file mode 100644 index 00000000000..dec559fceae --- /dev/null +++ b/erpnext/hr/doctype/interview_feedback/interview_feedback.js @@ -0,0 +1,54 @@ +// Copyright (c) 2021, Frappe Technologies Pvt. Ltd. and contributors +// For license information, please see license.txt + +frappe.ui.form.on('Interview Feedback', { + onload: function(frm) { + frm.ignore_doctypes_on_cancel_all = ['Interview']; + + frm.set_query('interview', function() { + return { + filters: { + docstatus: ['!=', 2] + } + }; + }); + }, + + interview_round: function(frm) { + frappe.call({ + method: 'erpnext.hr.doctype.interview.interview.get_expected_skill_set', + args: { + interview_round: frm.doc.interview_round + }, + callback: function(r) { + frm.set_value('skill_assessment', r.message); + } + }); + }, + + interview: function(frm) { + frappe.call({ + method: 'erpnext.hr.doctype.interview_feedback.interview_feedback.get_applicable_interviewers', + args: { + interview: frm.doc.interview || '' + }, + callback: function(r) { + frm.set_query('interviewer', function() { + return { + filters: { + name: ['in', r.message] + } + }; + }); + } + }); + + }, + + interviewer: function(frm) { + if (!frm.doc.interview) { + frappe.throw(__('Select Interview first')); + frm.set_value('interviewer', ''); + } + } +}); diff --git a/erpnext/hr/doctype/interview_feedback/interview_feedback.json b/erpnext/hr/doctype/interview_feedback/interview_feedback.json new file mode 100644 index 00000000000..6a2f7e86969 --- /dev/null +++ b/erpnext/hr/doctype/interview_feedback/interview_feedback.json @@ -0,0 +1,171 @@ +{ + "actions": [], + "autoname": "HR-INT-FEED-.####", + "creation": "2021-04-12 17:03:13.833285", + "doctype": "DocType", + "editable_grid": 1, + "engine": "InnoDB", + "field_order": [ + "details_section", + "interview", + "interview_round", + "job_applicant", + "column_break_3", + "interviewer", + "result", + "section_break_4", + "skill_assessment", + "average_rating", + "section_break_7", + "feedback", + "amended_from" + ], + "fields": [ + { + "allow_in_quick_entry": 1, + "fieldname": "interview", + "fieldtype": "Link", + "in_list_view": 1, + "in_standard_filter": 1, + "label": "Interview", + "options": "Interview", + "reqd": 1 + }, + { + "allow_in_quick_entry": 1, + "fetch_from": "interview.interview_round", + "fieldname": "interview_round", + "fieldtype": "Link", + "in_list_view": 1, + "in_standard_filter": 1, + "label": "Interview Round", + "options": "Interview Round", + "read_only": 1, + "reqd": 1 + }, + { + "allow_in_quick_entry": 1, + "fieldname": "interviewer", + "fieldtype": "Link", + "in_list_view": 1, + "in_standard_filter": 1, + "label": "Interviewer", + "options": "User", + "reqd": 1 + }, + { + "fieldname": "section_break_4", + "fieldtype": "Section Break", + "label": "Skill Assessment" + }, + { + "allow_in_quick_entry": 1, + "fieldname": "skill_assessment", + "fieldtype": "Table", + "options": "Skill Assessment", + "reqd": 1 + }, + { + "allow_in_quick_entry": 1, + "fieldname": "average_rating", + "fieldtype": "Rating", + "in_list_view": 1, + "label": "Average Rating", + "read_only": 1 + }, + { + "fieldname": "section_break_7", + "fieldtype": "Section Break", + "label": "Feedback" + }, + { + "fieldname": "column_break_3", + "fieldtype": "Column Break" + }, + { + "fieldname": "amended_from", + "fieldtype": "Link", + "label": "Amended From", + "no_copy": 1, + "options": "Interview Feedback", + "print_hide": 1, + "read_only": 1 + }, + { + "allow_in_quick_entry": 1, + "fieldname": "feedback", + "fieldtype": "Text" + }, + { + "fieldname": "result", + "fieldtype": "Select", + "in_list_view": 1, + "in_standard_filter": 1, + "label": "Result", + "options": "\nCleared\nRejected", + "reqd": 1 + }, + { + "fieldname": "details_section", + "fieldtype": "Section Break", + "label": "Details" + }, + { + "fetch_from": "interview.job_applicant", + "fieldname": "job_applicant", + "fieldtype": "Link", + "in_list_view": 1, + "in_standard_filter": 1, + "label": "Job Applicant", + "options": "Job Applicant", + "read_only": 1 + } + ], + "index_web_pages_for_search": 1, + "is_submittable": 1, + "links": [], + "modified": "2021-09-30 13:30:49.955352", + "modified_by": "Administrator", + "module": "HR", + "name": "Interview Feedback", + "owner": "Administrator", + "permissions": [ + { + "email": 1, + "export": 1, + "print": 1, + "read": 1, + "report": 1, + "role": "HR Manager", + "share": 1 + }, + { + "cancel": 1, + "create": 1, + "delete": 1, + "email": 1, + "export": 1, + "print": 1, + "read": 1, + "report": 1, + "role": "Interviewer", + "share": 1, + "submit": 1, + "write": 1 + }, + { + "email": 1, + "export": 1, + "print": 1, + "read": 1, + "report": 1, + "role": "HR User", + "share": 1 + } + ], + "quick_entry": 1, + "sort_field": "modified", + "sort_order": "DESC", + "title_field": "interviewer", + "track_changes": 1 +} \ No newline at end of file diff --git a/erpnext/hr/doctype/interview_feedback/interview_feedback.py b/erpnext/hr/doctype/interview_feedback/interview_feedback.py new file mode 100644 index 00000000000..d046458f196 --- /dev/null +++ b/erpnext/hr/doctype/interview_feedback/interview_feedback.py @@ -0,0 +1,86 @@ +# Copyright (c) 2021, Frappe Technologies Pvt. Ltd. and contributors +# For license information, please see license.txt + + +import frappe +from frappe import _ +from frappe.model.document import Document +from frappe.utils import flt, get_link_to_form, getdate + + +class InterviewFeedback(Document): + def validate(self): + self.validate_interviewer() + self.validate_interview_date() + self.validate_duplicate() + self.calculate_average_rating() + + def on_submit(self): + self.update_interview_details() + + def on_cancel(self): + self.update_interview_details() + + def validate_interviewer(self): + applicable_interviewers = get_applicable_interviewers(self.interview) + if self.interviewer not in applicable_interviewers: + frappe.throw(_('{0} is not allowed to submit Interview Feedback for the Interview: {1}').format( + frappe.bold(self.interviewer), frappe.bold(self.interview))) + + def validate_interview_date(self): + scheduled_date = frappe.db.get_value('Interview', self.interview, 'scheduled_on') + + if getdate() < getdate(scheduled_date) and self.docstatus == 1: + frappe.throw(_('{0} submission before {1} is not allowed').format( + frappe.bold('Interview Feedback'), + frappe.bold('Interview Scheduled Date') + )) + + def validate_duplicate(self): + duplicate_feedback = frappe.db.exists('Interview Feedback', { + 'interviewer': self.interviewer, + 'interview': self.interview, + 'docstatus': 1 + }) + + if duplicate_feedback: + frappe.throw(_('Feedback already submitted for the Interview {0}. Please cancel the previous Interview Feedback {1} to continue.').format( + self.interview, get_link_to_form('Interview Feedback', duplicate_feedback))) + + def calculate_average_rating(self): + total_rating = 0 + for d in self.skill_assessment: + if d.rating: + total_rating += d.rating + + self.average_rating = flt(total_rating / len(self.skill_assessment) if len(self.skill_assessment) else 0) + + def update_interview_details(self): + doc = frappe.get_doc('Interview', self.interview) + total_rating = 0 + + if self.docstatus == 2: + for entry in doc.interview_details: + if entry.interview_feedback == self.name: + entry.average_rating = entry.interview_feedback = entry.comments = entry.result = None + break + else: + for entry in doc.interview_details: + if entry.interviewer == self.interviewer: + entry.average_rating = self.average_rating + entry.interview_feedback = self.name + entry.comments = self.feedback + entry.result = self.result + + if entry.average_rating: + total_rating += entry.average_rating + + doc.average_rating = flt(total_rating / len(doc.interview_details) if len(doc.interview_details) else 0) + doc.save() + doc.notify_update() + + +@frappe.whitelist() +def get_applicable_interviewers(interview): + data = frappe.get_all('Interview Detail', filters={'parent': interview}, fields=['interviewer']) + return [d.interviewer for d in data] diff --git a/erpnext/hr/doctype/interview_feedback/test_interview_feedback.py b/erpnext/hr/doctype/interview_feedback/test_interview_feedback.py new file mode 100644 index 00000000000..4185f2827a5 --- /dev/null +++ b/erpnext/hr/doctype/interview_feedback/test_interview_feedback.py @@ -0,0 +1,101 @@ +# Copyright (c) 2021, Frappe Technologies Pvt. Ltd. and Contributors +# See license.txt + +import unittest + +import frappe +from frappe.utils import add_days, flt, getdate + +from erpnext.hr.doctype.interview.test_interview import ( + create_interview_and_dependencies, + create_skill_set, +) +from erpnext.hr.doctype.job_applicant.test_job_applicant import create_job_applicant + + +class TestInterviewFeedback(unittest.TestCase): + def test_validation_for_skill_set(self): + frappe.set_user("Administrator") + job_applicant = create_job_applicant() + interview = create_interview_and_dependencies(job_applicant.name, scheduled_on=add_days(getdate(), -1)) + skill_ratings = get_skills_rating(interview.interview_round) + + interviewer = interview.interview_details[0].interviewer + create_skill_set(['Leadership']) + + interview_feedback = create_interview_feedback(interview.name, interviewer, skill_ratings) + interview_feedback.append("skill_assessment", {"skill": 'Leadership', 'rating': 4}) + frappe.set_user(interviewer) + + self.assertRaises(frappe.ValidationError, interview_feedback.save) + + frappe.set_user("Administrator") + + def test_average_ratings_on_feedback_submission_and_cancellation(self): + job_applicant = create_job_applicant() + interview = create_interview_and_dependencies(job_applicant.name, scheduled_on=add_days(getdate(), -1)) + skill_ratings = get_skills_rating(interview.interview_round) + + # For First Interviewer Feedback + interviewer = interview.interview_details[0].interviewer + frappe.set_user(interviewer) + + # calculating Average + feedback_1 = create_interview_feedback(interview.name, interviewer, skill_ratings) + + total_rating = 0 + for d in feedback_1.skill_assessment: + if d.rating: + total_rating += d.rating + + avg_rating = flt(total_rating / len(feedback_1.skill_assessment) if len(feedback_1.skill_assessment) else 0) + + self.assertEqual(flt(avg_rating, 3), feedback_1.average_rating) + + avg_on_interview_detail = frappe.db.get_value('Interview Detail', { + 'parent': feedback_1.interview, + 'interviewer': feedback_1.interviewer, + 'interview_feedback': feedback_1.name + }, 'average_rating') + + # 1. average should be reflected in Interview Detail. + self.assertEqual(avg_on_interview_detail, round(feedback_1.average_rating)) + + '''For Second Interviewer Feedback''' + interviewer = interview.interview_details[1].interviewer + frappe.set_user(interviewer) + + feedback_2 = create_interview_feedback(interview.name, interviewer, skill_ratings) + interview.reload() + + feedback_2.cancel() + interview.reload() + + frappe.set_user("Administrator") + + def tearDown(self): + frappe.db.rollback() + + +def create_interview_feedback(interview, interviewer, skills_ratings): + interview_feedback = frappe.new_doc("Interview Feedback") + interview_feedback.interview = interview + interview_feedback.interviewer = interviewer + interview_feedback.result = "Cleared" + + for rating in skills_ratings: + interview_feedback.append("skill_assessment", rating) + + interview_feedback.save() + interview_feedback.submit() + + return interview_feedback + + +def get_skills_rating(interview_round): + import random + + skills = frappe.get_all("Expected Skill Set", filters={"parent": interview_round}, fields = ["skill"]) + for d in skills: + d["rating"] = random.randint(1, 5) + return skills diff --git a/erpnext/healthcare/doctype/descriptive_test_result/__init__.py b/erpnext/hr/doctype/interview_round/__init__.py similarity index 100% rename from erpnext/healthcare/doctype/descriptive_test_result/__init__.py rename to erpnext/hr/doctype/interview_round/__init__.py diff --git a/erpnext/hr/doctype/interview_round/interview_round.js b/erpnext/hr/doctype/interview_round/interview_round.js new file mode 100644 index 00000000000..6a608b03d25 --- /dev/null +++ b/erpnext/hr/doctype/interview_round/interview_round.js @@ -0,0 +1,24 @@ +// Copyright (c) 2021, Frappe Technologies Pvt. Ltd. and contributors +// For license information, please see license.txt + +frappe.ui.form.on("Interview Round", { + refresh: function(frm) { + if (!frm.doc.__islocal) { + frm.add_custom_button(__("Create Interview"), function() { + frm.events.create_interview(frm); + }); + } + }, + create_interview: function(frm) { + frappe.call({ + method: "erpnext.hr.doctype.interview_round.interview_round.create_interview", + args: { + doc: frm.doc + }, + callback: function (r) { + var doclist = frappe.model.sync(r.message); + frappe.set_route("Form", doclist[0].doctype, doclist[0].name); + } + }); + } +}); diff --git a/erpnext/hr/doctype/interview_round/interview_round.json b/erpnext/hr/doctype/interview_round/interview_round.json new file mode 100644 index 00000000000..9c95185e9ce --- /dev/null +++ b/erpnext/hr/doctype/interview_round/interview_round.json @@ -0,0 +1,118 @@ +{ + "actions": [], + "allow_rename": 1, + "autoname": "field:round_name", + "creation": "2021-04-12 12:57:19.902866", + "doctype": "DocType", + "editable_grid": 1, + "engine": "InnoDB", + "field_order": [ + "round_name", + "interview_type", + "interviewers", + "column_break_3", + "designation", + "expected_average_rating", + "expected_skills_section", + "expected_skill_set" + ], + "fields": [ + { + "fieldname": "round_name", + "fieldtype": "Data", + "in_list_view": 1, + "label": "Round Name", + "reqd": 1, + "unique": 1 + }, + { + "fieldname": "designation", + "fieldtype": "Link", + "label": "Designation", + "options": "Designation" + }, + { + "fieldname": "expected_skills_section", + "fieldtype": "Section Break", + "label": "Expected Skillset" + }, + { + "fieldname": "expected_skill_set", + "fieldtype": "Table", + "options": "Expected Skill Set", + "reqd": 1 + }, + { + "fieldname": "expected_average_rating", + "fieldtype": "Rating", + "label": "Expected Average Rating", + "reqd": 1 + }, + { + "fieldname": "column_break_3", + "fieldtype": "Column Break" + }, + { + "fieldname": "interview_type", + "fieldtype": "Link", + "label": "Interview Type", + "options": "Interview Type", + "reqd": 1 + }, + { + "fieldname": "interviewers", + "fieldtype": "Table MultiSelect", + "label": "Interviewers", + "options": "Interviewer" + } + ], + "index_web_pages_for_search": 1, + "links": [], + "modified": "2021-09-30 13:01:25.666660", + "modified_by": "Administrator", + "module": "HR", + "name": "Interview Round", + "owner": "Administrator", + "permissions": [ + { + "create": 1, + "delete": 1, + "email": 1, + "export": 1, + "print": 1, + "read": 1, + "report": 1, + "role": "HR User", + "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 + }, + { + "create": 1, + "delete": 1, + "email": 1, + "export": 1, + "print": 1, + "read": 1, + "report": 1, + "role": "Interviewer", + "select": 1, + "share": 1, + "write": 1 + } + ], + "sort_field": "modified", + "sort_order": "DESC", + "track_changes": 1 +} \ No newline at end of file diff --git a/erpnext/hr/doctype/interview_round/interview_round.py b/erpnext/hr/doctype/interview_round/interview_round.py new file mode 100644 index 00000000000..0f442c320ad --- /dev/null +++ b/erpnext/hr/doctype/interview_round/interview_round.py @@ -0,0 +1,33 @@ +# Copyright (c) 2021, Frappe Technologies Pvt. Ltd. and contributors +# For license information, please see license.txt + + +import json + +import frappe +from frappe.model.document import Document + + +class InterviewRound(Document): + pass + +@frappe.whitelist() +def create_interview(doc): + if isinstance(doc, str): + doc = json.loads(doc) + doc = frappe.get_doc(doc) + + interview = frappe.new_doc("Interview") + interview.interview_round = doc.name + interview.designation = doc.designation + + if doc.interviewers: + interview.interview_details = [] + for data in doc.interviewers: + interview.append("interview_details", { + "interviewer": data.user + }) + return interview + + + diff --git a/erpnext/hr/doctype/interview_round/test_interview_round.py b/erpnext/hr/doctype/interview_round/test_interview_round.py new file mode 100644 index 00000000000..dcec9419c07 --- /dev/null +++ b/erpnext/hr/doctype/interview_round/test_interview_round.py @@ -0,0 +1,11 @@ +# Copyright (c) 2021, Frappe Technologies Pvt. Ltd. and Contributors +# See license.txt + +import unittest + +# import frappe + + +class TestInterviewRound(unittest.TestCase): + pass + diff --git a/erpnext/healthcare/doctype/descriptive_test_template/__init__.py b/erpnext/hr/doctype/interview_type/__init__.py similarity index 100% rename from erpnext/healthcare/doctype/descriptive_test_template/__init__.py rename to erpnext/hr/doctype/interview_type/__init__.py diff --git a/erpnext/hr/doctype/interview_type/interview_type.js b/erpnext/hr/doctype/interview_type/interview_type.js new file mode 100644 index 00000000000..af77b527d4d --- /dev/null +++ b/erpnext/hr/doctype/interview_type/interview_type.js @@ -0,0 +1,8 @@ +// Copyright (c) 2021, Frappe Technologies Pvt. Ltd. and contributors +// For license information, please see license.txt + +frappe.ui.form.on('Interview Type', { + // refresh: function(frm) { + + // } +}); diff --git a/erpnext/buying/doctype/supplier_item_group/supplier_item_group.json b/erpnext/hr/doctype/interview_type/interview_type.json similarity index 61% rename from erpnext/buying/doctype/supplier_item_group/supplier_item_group.json rename to erpnext/hr/doctype/interview_type/interview_type.json index 1971458f61e..14636a18cb3 100644 --- a/erpnext/buying/doctype/supplier_item_group/supplier_item_group.json +++ b/erpnext/hr/doctype/interview_type/interview_type.json @@ -1,37 +1,33 @@ { "actions": [], - "creation": "2021-05-07 18:16:40.621421", + "allow_rename": 1, + "autoname": "Prompt", + "creation": "2021-04-12 14:44:40.664034", "doctype": "DocType", "editable_grid": 1, "engine": "InnoDB", "field_order": [ - "supplier", - "item_group" + "description" ], "fields": [ { - "fieldname": "supplier", - "fieldtype": "Link", + "fieldname": "description", + "fieldtype": "Text", "in_list_view": 1, - "label": "Supplier", - "options": "Supplier", - "reqd": 1 - }, - { - "fieldname": "item_group", - "fieldtype": "Link", - "in_list_view": 1, - "label": "Item Group", - "options": "Item Group", - "reqd": 1 + "label": "Description" } ], "index_web_pages_for_search": 1, - "links": [], - "modified": "2021-05-19 13:48:16.742303", + "links": [ + { + "link_doctype": "Interview Round", + "link_fieldname": "interview_type" + } + ], + "modified": "2021-09-30 13:00:16.471518", "modified_by": "Administrator", - "module": "Buying", - "name": "Supplier Item Group", + "module": "HR", + "name": "Interview Type", "owner": "Administrator", "permissions": [ { @@ -54,7 +50,7 @@ "print": 1, "read": 1, "report": 1, - "role": "Purchase User", + "role": "HR Manager", "share": 1, "write": 1 }, @@ -66,7 +62,7 @@ "print": 1, "read": 1, "report": 1, - "role": "Purchase Manager", + "role": "HR User", "share": 1, "write": 1 } diff --git a/erpnext/hr/doctype/interview_type/interview_type.py b/erpnext/hr/doctype/interview_type/interview_type.py new file mode 100644 index 00000000000..f5ebda427b8 --- /dev/null +++ b/erpnext/hr/doctype/interview_type/interview_type.py @@ -0,0 +1,10 @@ +# Copyright (c) 2021, Frappe Technologies Pvt. Ltd. and contributors +# For license information, please see license.txt + + +# import frappe +from frappe.model.document import Document + + +class InterviewType(Document): + pass diff --git a/erpnext/hr/doctype/interview_type/test_interview_type.py b/erpnext/hr/doctype/interview_type/test_interview_type.py new file mode 100644 index 00000000000..96fdfcad686 --- /dev/null +++ b/erpnext/hr/doctype/interview_type/test_interview_type.py @@ -0,0 +1,9 @@ +# Copyright (c) 2021, Frappe Technologies Pvt. Ltd. and Contributors +# See license.txt + +# import frappe +import unittest + + +class TestInterviewType(unittest.TestCase): + pass diff --git a/erpnext/healthcare/doctype/diagnosis/__init__.py b/erpnext/hr/doctype/interviewer/__init__.py similarity index 100% rename from erpnext/healthcare/doctype/diagnosis/__init__.py rename to erpnext/hr/doctype/interviewer/__init__.py diff --git a/erpnext/healthcare/doctype/body_part_link/body_part_link.json b/erpnext/hr/doctype/interviewer/interviewer.json similarity index 57% rename from erpnext/healthcare/doctype/body_part_link/body_part_link.json rename to erpnext/hr/doctype/interviewer/interviewer.json index 400b7c6fe81..a37b8b0e4e5 100644 --- a/erpnext/healthcare/doctype/body_part_link/body_part_link.json +++ b/erpnext/hr/doctype/interviewer/interviewer.json @@ -1,31 +1,30 @@ { "actions": [], - "creation": "2020-04-10 12:23:15.259816", + "creation": "2021-04-12 17:38:19.354734", "doctype": "DocType", "editable_grid": 1, "engine": "InnoDB", "field_order": [ - "body_part" + "user" ], "fields": [ { - "fieldname": "body_part", + "fieldname": "user", "fieldtype": "Link", "in_list_view": 1, - "label": "Body Part", - "options": "Body Part", - "reqd": 1 + "label": "User", + "options": "User" } ], + "index_web_pages_for_search": 1, "istable": 1, "links": [], - "modified": "2020-04-10 12:25:23.101749", + "modified": "2021-04-13 13:41:35.817568", "modified_by": "Administrator", - "module": "Healthcare", - "name": "Body Part Link", + "module": "HR", + "name": "Interviewer", "owner": "Administrator", "permissions": [], - "quick_entry": 1, "sort_field": "modified", "sort_order": "DESC", "track_changes": 1 diff --git a/erpnext/hr/doctype/interviewer/interviewer.py b/erpnext/hr/doctype/interviewer/interviewer.py new file mode 100644 index 00000000000..2dc4a143254 --- /dev/null +++ b/erpnext/hr/doctype/interviewer/interviewer.py @@ -0,0 +1,10 @@ +# Copyright (c) 2021, Frappe Technologies Pvt. Ltd. and contributors +# For license information, please see license.txt + + +# import frappe +from frappe.model.document import Document + + +class Interviewer(Document): + pass diff --git a/erpnext/hr/doctype/job_applicant/job_applicant.js b/erpnext/hr/doctype/job_applicant/job_applicant.js index 7658bc93539..d7b1c6c9df3 100644 --- a/erpnext/hr/doctype/job_applicant/job_applicant.js +++ b/erpnext/hr/doctype/job_applicant/job_applicant.js @@ -8,6 +8,24 @@ cur_frm.email_field = "email_id"; frappe.ui.form.on("Job Applicant", { refresh: function(frm) { + frm.set_query("job_title", function() { + return { + filters: { + 'status': 'Open' + } + }; + }); + frm.events.create_custom_buttons(frm); + frm.events.make_dashboard(frm); + }, + + create_custom_buttons: function(frm) { + if (!frm.doc.__islocal && frm.doc.status !== "Rejected" && frm.doc.status !== "Accepted") { + frm.add_custom_button(__("Create Interview"), function() { + frm.events.create_dialog(frm); + }); + } + if (!frm.doc.__islocal) { if (frm.doc.__onload && frm.doc.__onload.job_offer) { $('[data-doctype="Employee Onboarding"]').find("button").show(); @@ -28,14 +46,57 @@ frappe.ui.form.on("Job Applicant", { }); } } + }, - frm.set_query("job_title", function() { - return { - filters: { - 'status': 'Open' - } - }; + make_dashboard: function(frm) { + frappe.call({ + method: "erpnext.hr.doctype.job_applicant.job_applicant.get_interview_details", + args: { + job_applicant: frm.doc.name + }, + callback: function(r) { + $("div").remove(".form-dashboard-section.custom"); + frm.dashboard.add_section( + frappe.render_template('job_applicant_dashboard', { + data: r.message + }), + __("Interview Summary") + ); + } }); + }, + create_dialog: function(frm) { + let d = new frappe.ui.Dialog({ + title: 'Enter Interview Round', + fields: [ + { + label: 'Interview Round', + fieldname: 'interview_round', + fieldtype: 'Link', + options: 'Interview Round' + }, + ], + primary_action_label: 'Create Interview', + primary_action(values) { + frm.events.create_interview(frm, values); + d.hide(); + } + }); + d.show(); + }, + + create_interview: function (frm, values) { + frappe.call({ + method: "erpnext.hr.doctype.job_applicant.job_applicant.create_interview", + args: { + doc: frm.doc, + interview_round: values.interview_round + }, + callback: function (r) { + var doclist = frappe.model.sync(r.message); + frappe.set_route("Form", doclist[0].doctype, doclist[0].name); + } + }); } }); diff --git a/erpnext/hr/doctype/job_applicant/job_applicant.json b/erpnext/hr/doctype/job_applicant/job_applicant.json index bcea5f50d93..200f675221b 100644 --- a/erpnext/hr/doctype/job_applicant/job_applicant.json +++ b/erpnext/hr/doctype/job_applicant/job_applicant.json @@ -9,16 +9,20 @@ "email_append_to": 1, "engine": "InnoDB", "field_order": [ + "details_section", "applicant_name", "email_id", "phone_number", "country", - "status", "column_break_3", "job_title", + "designation", + "status", + "source_and_rating_section", "source", "source_name", "employee_referral", + "column_break_13", "applicant_rating", "section_break_6", "notes", @@ -84,7 +88,8 @@ }, { "fieldname": "section_break_6", - "fieldtype": "Section Break" + "fieldtype": "Section Break", + "label": "Resume" }, { "fieldname": "cover_letter", @@ -160,13 +165,34 @@ "label": "Employee Referral", "options": "Employee Referral", "read_only": 1 + }, + { + "fieldname": "details_section", + "fieldtype": "Section Break", + "label": "Details" + }, + { + "fieldname": "source_and_rating_section", + "fieldtype": "Section Break", + "label": "Source and Rating" + }, + { + "fieldname": "column_break_13", + "fieldtype": "Column Break" + }, + { + "fetch_from": "job_opening.designation", + "fieldname": "designation", + "fieldtype": "Link", + "label": "Designation", + "options": "Designation" } ], "icon": "fa fa-user", "idx": 1, "index_web_pages_for_search": 1, "links": [], - "modified": "2021-03-24 15:51:11.117517", + "modified": "2021-09-29 23:06:10.904260", "modified_by": "Administrator", "module": "HR", "name": "Job Applicant", diff --git a/erpnext/hr/doctype/job_applicant/job_applicant.py b/erpnext/hr/doctype/job_applicant/job_applicant.py index 6971e5b4fef..abaa50c84ce 100644 --- a/erpnext/hr/doctype/job_applicant/job_applicant.py +++ b/erpnext/hr/doctype/job_applicant/job_applicant.py @@ -3,12 +3,13 @@ # For license information, please see license.txt -from __future__ import unicode_literals import frappe from frappe import _ from frappe.model.document import Document -from frappe.utils import comma_and, validate_email_address +from frappe.utils import validate_email_address + +from erpnext.hr.doctype.interview.interview import get_interviewers class DuplicationError(frappe.ValidationError): pass @@ -26,7 +27,6 @@ class JobApplicant(Document): self.name = " - ".join(keys) def validate(self): - self.check_email_id_is_unique() if self.email_id: validate_email_address(self.email_id, True) @@ -44,11 +44,43 @@ class JobApplicant(Document): elif self.status in ["Accepted", "Rejected"]: emp_ref.db_set("status", self.status) +@frappe.whitelist() +def create_interview(doc, interview_round): + import json - def check_email_id_is_unique(self): - if self.email_id: - names = frappe.db.sql_list("""select name from `tabJob Applicant` - where email_id=%s and name!=%s and job_title=%s""", (self.email_id, self.name, self.job_title)) - if names: - frappe.throw(_("Email Address must be unique, already exists for {0}").format(comma_and(names)), frappe.DuplicateEntryError) + if isinstance(doc, str): + doc = json.loads(doc) + doc = frappe.get_doc(doc) + + round_designation = frappe.db.get_value("Interview Round", interview_round, "designation") + + if round_designation and doc.designation and round_designation != doc.designation: + frappe.throw(_("Interview Round {0} is only applicable for the Designation {1}").format(interview_round, round_designation)) + + interview = frappe.new_doc("Interview") + interview.interview_round = interview_round + interview.job_applicant = doc.name + interview.designation = doc.designation + interview.resume_link = doc.resume_link + interview.job_opening = doc.job_title + interviewer_detail = get_interviewers(interview_round) + + for d in interviewer_detail: + interview.append("interview_details", { + "interviewer": d.interviewer + }) + return interview + +@frappe.whitelist() +def get_interview_details(job_applicant): + interview_details = frappe.db.get_all("Interview", + filters={"job_applicant":job_applicant, "docstatus": ["!=", 2]}, + fields=["name", "interview_round", "expected_average_rating", "average_rating", "status"] + ) + interview_detail_map = {} + + for detail in interview_details: + interview_detail_map[detail.name] = detail + + return interview_detail_map diff --git a/erpnext/hr/doctype/job_applicant/job_applicant_dashboard.html b/erpnext/hr/doctype/job_applicant/job_applicant_dashboard.html new file mode 100644 index 00000000000..c286787a556 --- /dev/null +++ b/erpnext/hr/doctype/job_applicant/job_applicant_dashboard.html @@ -0,0 +1,44 @@ + +{% if not jQuery.isEmptyObject(data) %} + + + + + + + + + + + + + {% for(const [key, value] of Object.entries(data)) { %} + + + + + + + + {% } %} + +
{{ __("Interview") }}{{ __("Interview Round") }}{{ __("Status") }}{{ __("Expected Rating") }}{{ __("Rating") }}
{%= key %} {%= value["interview_round"] %} {%= value["status"] %} + {% for (i = 0; i < value["expected_average_rating"]; i++) { %} + + {% } %} + {% for (i = 0; i < (5-value["expected_average_rating"]); i++) { %} + + {% } %} + + {% if(value["average_rating"]){ %} + {% for (i = 0; i < value["average_rating"]; i++) { %} + + {% } %} + {% for (i = 0; i < (5-value["average_rating"]); i++) { %} + + {% } %} + {% } %} +
+{% else %} +

No Interview has been scheduled.

+{% endif %} diff --git a/erpnext/hr/doctype/job_applicant/job_applicant_dashboard.py b/erpnext/hr/doctype/job_applicant/job_applicant_dashboard.py index c0059431cfc..56331ac132f 100644 --- a/erpnext/hr/doctype/job_applicant/job_applicant_dashboard.py +++ b/erpnext/hr/doctype/job_applicant/job_applicant_dashboard.py @@ -1,15 +1,15 @@ -from __future__ import unicode_literals - - def get_data(): - return { - 'fieldname': 'job_applicant', - 'transactions': [ - { - 'items': ['Employee', 'Employee Onboarding'] - }, - { - 'items': ['Job Offer'] - }, - ], - } + return { + 'fieldname': 'job_applicant', + 'transactions': [ + { + 'items': ['Employee', 'Employee Onboarding'] + }, + { + 'items': ['Job Offer', 'Appointment Letter'] + }, + { + 'items': ['Interview'] + } + ], + } diff --git a/erpnext/hr/doctype/job_applicant/test_job_applicant.py b/erpnext/hr/doctype/job_applicant/test_job_applicant.py index e583e25eae0..36dcf6b0740 100644 --- a/erpnext/hr/doctype/job_applicant/test_job_applicant.py +++ b/erpnext/hr/doctype/job_applicant/test_job_applicant.py @@ -1,13 +1,12 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors and Contributors # See license.txt -from __future__ import unicode_literals import unittest import frappe -# test_records = frappe.get_test_records('Job Applicant') +from erpnext.hr.doctype.designation.test_designation import create_designation + class TestJobApplicant(unittest.TestCase): pass @@ -25,7 +24,8 @@ def create_job_applicant(**args): job_applicant = frappe.get_doc({ "doctype": "Job Applicant", - "status": args.status or "Open" + "status": args.status or "Open", + "designation": create_designation().name }) job_applicant.update(filters) diff --git a/erpnext/hr/doctype/job_applicant_source/job_applicant_source.py b/erpnext/hr/doctype/job_applicant_source/job_applicant_source.py index 9139584aa5c..1f208c14c60 100644 --- a/erpnext/hr/doctype/job_applicant_source/job_applicant_source.py +++ b/erpnext/hr/doctype/job_applicant_source/job_applicant_source.py @@ -1,8 +1,6 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2018, Frappe Technologies Pvt. Ltd. and contributors # For license information, please see license.txt -from __future__ import unicode_literals from frappe.model.document import Document diff --git a/erpnext/hr/doctype/job_applicant_source/test_job_applicant_source.py b/erpnext/hr/doctype/job_applicant_source/test_job_applicant_source.py index 0c29124560b..cee5daf783e 100644 --- a/erpnext/hr/doctype/job_applicant_source/test_job_applicant_source.py +++ b/erpnext/hr/doctype/job_applicant_source/test_job_applicant_source.py @@ -1,7 +1,5 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2018, Frappe Technologies Pvt. Ltd. and Contributors # See license.txt -from __future__ import unicode_literals import unittest diff --git a/erpnext/hr/doctype/job_offer/job_offer.py b/erpnext/hr/doctype/job_offer/job_offer.py index 07a7809891d..39f471929b4 100644 --- a/erpnext/hr/doctype/job_offer/job_offer.py +++ b/erpnext/hr/doctype/job_offer/job_offer.py @@ -1,7 +1,6 @@ # Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors and contributors # For license information, please see license.txt -from __future__ import unicode_literals import frappe from frappe import _ diff --git a/erpnext/hr/doctype/job_offer/test_job_offer.py b/erpnext/hr/doctype/job_offer/test_job_offer.py index 3f3eca17e62..d94e03ca63f 100644 --- a/erpnext/hr/doctype/job_offer/test_job_offer.py +++ b/erpnext/hr/doctype/job_offer/test_job_offer.py @@ -1,6 +1,5 @@ # Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors and Contributors # See license.txt -from __future__ import unicode_literals import unittest @@ -32,6 +31,7 @@ class TestJobOffer(unittest.TestCase): self.assertTrue(frappe.db.exists("Job Offer", job_offer.name)) def test_job_applicant_update(self): + frappe.db.set_value("HR Settings", None, "check_vacancies", 0) create_staffing_plan() job_applicant = create_job_applicant(email_id="test_job_applicants@example.com") job_offer = create_job_offer(job_applicant=job_applicant.name) @@ -43,7 +43,11 @@ class TestJobOffer(unittest.TestCase): job_offer.status = "Rejected" job_offer.submit() job_applicant.reload() - self.assertEqual(job_applicant.status, "Rejected") + self.assertEquals(job_applicant.status, "Rejected") + frappe.db.set_value("HR Settings", None, "check_vacancies", 1) + + def tearDown(self): + frappe.db.sql("DELETE FROM `tabJob Offer` WHERE 1") def create_job_offer(**args): args = frappe._dict(args) diff --git a/erpnext/hr/doctype/job_offer_term/job_offer_term.py b/erpnext/hr/doctype/job_offer_term/job_offer_term.py index 573cc6ae21d..d2eae467e41 100644 --- a/erpnext/hr/doctype/job_offer_term/job_offer_term.py +++ b/erpnext/hr/doctype/job_offer_term/job_offer_term.py @@ -1,7 +1,6 @@ # Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors and contributors # For license information, please see license.txt -from __future__ import unicode_literals from frappe.model.document import Document diff --git a/erpnext/hr/doctype/job_opening/job_opening.py b/erpnext/hr/doctype/job_opening/job_opening.py index 38d9a718170..d53daf17d87 100644 --- a/erpnext/hr/doctype/job_opening/job_opening.py +++ b/erpnext/hr/doctype/job_opening/job_opening.py @@ -3,7 +3,6 @@ # For license information, please see license.txt -from __future__ import unicode_literals import frappe from frappe import _ diff --git a/erpnext/hr/doctype/job_opening/job_opening_dashboard.py b/erpnext/hr/doctype/job_opening/job_opening_dashboard.py index a13e2a7c23a..67600dc20e2 100644 --- a/erpnext/hr/doctype/job_opening/job_opening_dashboard.py +++ b/erpnext/hr/doctype/job_opening/job_opening_dashboard.py @@ -1,6 +1,3 @@ -from __future__ import unicode_literals - - def get_data(): return { 'fieldname': 'job_title', diff --git a/erpnext/hr/doctype/job_opening/test_job_opening.py b/erpnext/hr/doctype/job_opening/test_job_opening.py index a66975c91ed..a1c3a1d49e3 100644 --- a/erpnext/hr/doctype/job_opening/test_job_opening.py +++ b/erpnext/hr/doctype/job_opening/test_job_opening.py @@ -1,7 +1,5 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors # See license.txt -from __future__ import unicode_literals import unittest diff --git a/erpnext/hr/doctype/leave_allocation/__init__.py b/erpnext/hr/doctype/leave_allocation/__init__.py index baffc488252..e69de29bb2d 100755 --- a/erpnext/hr/doctype/leave_allocation/__init__.py +++ b/erpnext/hr/doctype/leave_allocation/__init__.py @@ -1 +0,0 @@ -from __future__ import unicode_literals diff --git a/erpnext/hr/doctype/leave_allocation/leave_allocation.js b/erpnext/hr/doctype/leave_allocation/leave_allocation.js index d94764104d0..9742387c16a 100755 --- a/erpnext/hr/doctype/leave_allocation/leave_allocation.js +++ b/erpnext/hr/doctype/leave_allocation/leave_allocation.js @@ -1,14 +1,14 @@ // Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors // License: GNU General Public License v3. See license.txt -cur_frm.add_fetch('employee','employee_name','employee_name'); +cur_frm.add_fetch('employee', 'employee_name', 'employee_name'); frappe.ui.form.on("Leave Allocation", { onload: function(frm) { // Ignore cancellation of doctype on cancel all. frm.ignore_doctypes_on_cancel_all = ["Leave Ledger Entry"]; - if(!frm.doc.from_date) frm.set_value("from_date", frappe.datetime.get_today()); + if (!frm.doc.from_date) frm.set_value("from_date", frappe.datetime.get_today()); frm.set_query("employee", function() { return { @@ -25,9 +25,9 @@ frappe.ui.form.on("Leave Allocation", { }, refresh: function(frm) { - if(frm.doc.docstatus === 1 && frm.doc.expired) { + if (frm.doc.docstatus === 1 && frm.doc.expired) { var valid_expiry = moment(frappe.datetime.get_today()).isBetween(frm.doc.from_date, frm.doc.to_date); - if(valid_expiry) { + if (valid_expiry) { // expire current allocation frm.add_custom_button(__('Expire Allocation'), function() { frm.trigger("expire_allocation"); @@ -44,8 +44,8 @@ frappe.ui.form.on("Leave Allocation", { 'expiry_date': frappe.datetime.get_today() }, freeze: true, - callback: function(r){ - if(!r.exc){ + callback: function(r) { + if (!r.exc) { frappe.msgprint(__("Allocation Expired!")); } frm.refresh(); @@ -77,8 +77,8 @@ frappe.ui.form.on("Leave Allocation", { }, leave_policy: function(frm) { - if(frm.doc.leave_policy && frm.doc.leave_type) { - frappe.db.get_value("Leave Policy Detail",{ + if (frm.doc.leave_policy && frm.doc.leave_type) { + frappe.db.get_value("Leave Policy Detail", { 'parent': frm.doc.leave_policy, 'leave_type': frm.doc.leave_type }, 'annual_allocation', (r) => { @@ -91,13 +91,41 @@ frappe.ui.form.on("Leave Allocation", { return frappe.call({ method: "set_total_leaves_allocated", doc: frm.doc, - callback: function(r) { + callback: function() { frm.refresh_fields(); } - }) + }); } else if (cint(frm.doc.carry_forward) == 0) { frm.set_value("unused_leaves", 0); frm.set_value("total_leaves_allocated", flt(frm.doc.new_leaves_allocated)); } } }); + +frappe.tour["Leave Allocation"] = [ + { + fieldname: "employee", + title: "Employee", + description: __("Select the Employee for which you want to allocate leaves.") + }, + { + fieldname: "leave_type", + title: "Leave Type", + description: __("Select the Leave Type like Sick leave, Privilege Leave, Casual Leave, etc.") + }, + { + fieldname: "from_date", + title: "From Date", + description: __("Select the date from which this Leave Allocation will be valid.") + }, + { + fieldname: "to_date", + title: "To Date", + description: __("Select the date after which this Leave Allocation will expire.") + }, + { + fieldname: "new_leaves_allocated", + title: "New Leaves Allocated", + description: __("Enter the number of leaves you want to allocate for the period.") + } +]; diff --git a/erpnext/hr/doctype/leave_allocation/leave_allocation.json b/erpnext/hr/doctype/leave_allocation/leave_allocation.json index 3a6539ece9e..52ee463db02 100644 --- a/erpnext/hr/doctype/leave_allocation/leave_allocation.json +++ b/erpnext/hr/doctype/leave_allocation/leave_allocation.json @@ -219,7 +219,8 @@ "fieldname": "leave_policy_assignment", "fieldtype": "Link", "label": "Leave Policy Assignment", - "options": "Leave Policy Assignment" + "options": "Leave Policy Assignment", + "read_only": 1 }, { "fetch_from": "employee.company", @@ -236,7 +237,7 @@ "index_web_pages_for_search": 1, "is_submittable": 1, "links": [], - "modified": "2021-06-03 15:28:26.335104", + "modified": "2021-10-01 15:28:26.335104", "modified_by": "Administrator", "module": "HR", "name": "Leave Allocation", diff --git a/erpnext/hr/doctype/leave_allocation/leave_allocation.py b/erpnext/hr/doctype/leave_allocation/leave_allocation.py index e4886d7ae72..232118fd67c 100755 --- a/erpnext/hr/doctype/leave_allocation/leave_allocation.py +++ b/erpnext/hr/doctype/leave_allocation/leave_allocation.py @@ -1,7 +1,6 @@ # Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors # License: GNU General Public License v3. See license.txt -from __future__ import unicode_literals import frappe from frappe import _ diff --git a/erpnext/hr/doctype/leave_allocation/leave_allocation_dashboard.py b/erpnext/hr/doctype/leave_allocation/leave_allocation_dashboard.py index 84423bd2b45..631beef4359 100644 --- a/erpnext/hr/doctype/leave_allocation/leave_allocation_dashboard.py +++ b/erpnext/hr/doctype/leave_allocation/leave_allocation_dashboard.py @@ -1,6 +1,3 @@ -from __future__ import unicode_literals - - def get_data(): return { 'fieldname': 'leave_allocation', diff --git a/erpnext/hr/doctype/leave_allocation/test_leave_allocation.py b/erpnext/hr/doctype/leave_allocation/test_leave_allocation.py index b1850562e3a..46401a2dd8c 100644 --- a/erpnext/hr/doctype/leave_allocation/test_leave_allocation.py +++ b/erpnext/hr/doctype/leave_allocation/test_leave_allocation.py @@ -1,5 +1,3 @@ -from __future__ import unicode_literals - import unittest import frappe diff --git a/erpnext/hr/doctype/leave_application/__init__.py b/erpnext/hr/doctype/leave_application/__init__.py index baffc488252..e69de29bb2d 100755 --- a/erpnext/hr/doctype/leave_application/__init__.py +++ b/erpnext/hr/doctype/leave_application/__init__.py @@ -1 +0,0 @@ -from __future__ import unicode_literals diff --git a/erpnext/hr/doctype/leave_application/leave_application.js b/erpnext/hr/doctype/leave_application/leave_application.js index 9ccb915908f..9e8cb5516f3 100755 --- a/erpnext/hr/doctype/leave_application/leave_application.js +++ b/erpnext/hr/doctype/leave_application/leave_application.js @@ -1,8 +1,8 @@ // Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors // License: GNU General Public License v3. See license.txt -cur_frm.add_fetch('employee','employee_name','employee_name'); -cur_frm.add_fetch('employee','company','company'); +cur_frm.add_fetch('employee', 'employee_name', 'employee_name'); +cur_frm.add_fetch('employee', 'company', 'company'); frappe.ui.form.on("Leave Application", { setup: function(frm) { @@ -19,7 +19,6 @@ frappe.ui.form.on("Leave Application", { frm.set_query("employee", erpnext.queries.employee); }, onload: function(frm) { - // Ignore cancellation of doctype on cancel all. frm.ignore_doctypes_on_cancel_all = ["Leave Ledger Entry"]; @@ -42,9 +41,9 @@ frappe.ui.form.on("Leave Application", { }, validate: function(frm) { - if (frm.doc.from_date == frm.doc.to_date && frm.doc.half_day == 1){ + if (frm.doc.from_date == frm.doc.to_date && frm.doc.half_day == 1) { frm.doc.half_day_date = frm.doc.from_date; - }else if (frm.doc.half_day == 0){ + } else if (frm.doc.half_day == 0) { frm.doc.half_day_date = ""; } frm.toggle_reqd("half_day_date", frm.doc.half_day == 1); @@ -79,14 +78,14 @@ frappe.ui.form.on("Leave Application", { __("Allocated Leaves") ); frm.dashboard.show(); - let allowed_leave_types = Object.keys(leave_details); + let allowed_leave_types = Object.keys(leave_details); // lwps should be allowed, lwps don't have any allocation allowed_leave_types = allowed_leave_types.concat(lwps); - frm.set_query('leave_type', function(){ + frm.set_query('leave_type', function() { return { - filters : [ + filters: [ ['leave_type_name', 'in', allowed_leave_types] ] }; @@ -99,7 +98,7 @@ frappe.ui.form.on("Leave Application", { frm.trigger("calculate_total_days"); } cur_frm.set_intro(""); - if(frm.doc.__islocal && !in_list(frappe.user_roles, "Employee")) { + if (frm.doc.__islocal && !in_list(frappe.user_roles, "Employee")) { frm.set_intro(__("Fill the form and save it")); } @@ -118,7 +117,7 @@ frappe.ui.form.on("Leave Application", { }, leave_approver: function(frm) { - if(frm.doc.leave_approver){ + if (frm.doc.leave_approver) { frm.set_value("leave_approver_name", frappe.user.full_name(frm.doc.leave_approver)); } }, @@ -131,12 +130,10 @@ frappe.ui.form.on("Leave Application", { if (frm.doc.half_day) { if (frm.doc.from_date == frm.doc.to_date) { frm.set_value("half_day_date", frm.doc.from_date); - } - else { + } else { frm.trigger("half_day_datepicker"); } - } - else { + } else { frm.set_value("half_day_date", ""); } frm.trigger("calculate_total_days"); @@ -163,11 +160,11 @@ frappe.ui.form.on("Leave Application", { half_day_datepicker.update({ minDate: frappe.datetime.str_to_obj(frm.doc.from_date), maxDate: frappe.datetime.str_to_obj(frm.doc.to_date) - }) + }); }, get_leave_balance: function(frm) { - if(frm.doc.docstatus==0 && frm.doc.employee && frm.doc.leave_type && frm.doc.from_date && frm.doc.to_date) { + if (frm.doc.docstatus === 0 && frm.doc.employee && frm.doc.leave_type && frm.doc.from_date && frm.doc.to_date) { return frappe.call({ method: "erpnext.hr.doctype.leave_application.leave_application.get_leave_balance_on", args: { @@ -177,11 +174,10 @@ frappe.ui.form.on("Leave Application", { leave_type: frm.doc.leave_type, consider_all_leaves_in_the_allocation_period: true }, - callback: function(r) { + callback: function (r) { if (!r.exc && r.message) { frm.set_value('leave_balance', r.message); - } - else { + } else { frm.set_value('leave_balance', "0"); } } @@ -190,12 +186,12 @@ frappe.ui.form.on("Leave Application", { }, calculate_total_days: function(frm) { - if(frm.doc.from_date && frm.doc.to_date && frm.doc.employee && frm.doc.leave_type) { + if (frm.doc.from_date && frm.doc.to_date && frm.doc.employee && frm.doc.leave_type) { var from_date = Date.parse(frm.doc.from_date); var to_date = Date.parse(frm.doc.to_date); - if(to_date < from_date){ + if (to_date < from_date) { frappe.msgprint(__("To Date cannot be less than From Date")); frm.set_value('to_date', ''); return; @@ -222,7 +218,7 @@ frappe.ui.form.on("Leave Application", { }, set_leave_approver: function(frm) { - if(frm.doc.employee) { + if (frm.doc.employee) { // server call is done to include holidays in leave days calculations return frappe.call({ method: 'erpnext.hr.doctype.leave_application.leave_application.get_leave_approver', @@ -238,3 +234,36 @@ frappe.ui.form.on("Leave Application", { } } }); + +frappe.tour["Leave Application"] = [ + { + fieldname: "employee", + title: "Employee", + description: __("Select the Employee.") + }, + { + fieldname: "leave_type", + title: "Leave Type", + description: __("Select type of leave the employee wants to apply for, like Sick Leave, Privilege Leave, Casual Leave, etc.") + }, + { + fieldname: "from_date", + title: "From Date", + description: __("Select the start date for your Leave Application.") + }, + { + fieldname: "to_date", + title: "To Date", + description: __("Select the end date for your Leave Application.") + }, + { + fieldname: "half_day", + title: "Half Day", + description: __("To apply for a Half Day check 'Half Day' and select the Half Day Date") + }, + { + fieldname: "leave_approver", + title: "Leave Approver", + description: __("Select your Leave Approver i.e. the person who approves or rejects your leaves.") + } +]; diff --git a/erpnext/hr/doctype/leave_application/leave_application.py b/erpnext/hr/doctype/leave_application/leave_application.py index 9e6fc6d0f14..1dc5b31461e 100755 --- a/erpnext/hr/doctype/leave_application/leave_application.py +++ b/erpnext/hr/doctype/leave_application/leave_application.py @@ -1,7 +1,6 @@ # Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors # License: GNU General Public License v3. See license.txt -from __future__ import unicode_literals import frappe from frappe import _ @@ -76,6 +75,7 @@ class LeaveApplication(Document): # notify leave applier about approval if frappe.db.get_single_value("HR Settings", "send_leave_notification"): self.notify_employee() + self.create_leave_ledger_entry() self.reload() @@ -108,7 +108,13 @@ class LeaveApplication(Document): if frappe.db.get_single_value("HR Settings", "restrict_backdated_leave_application"): if self.from_date and getdate(self.from_date) < getdate(): allowed_role = frappe.db.get_single_value("HR Settings", "role_allowed_to_create_backdated_leave_application") - if allowed_role not in frappe.get_roles(): + user = frappe.get_doc("User", frappe.session.user) + user_roles = [d.role for d in user.roles] + if not allowed_role: + frappe.throw(_("Backdated Leave Application is restricted. Please set the {} in {}").format( + frappe.bold("Role Allowed to Create Backdated Leave Application"), get_link_to_form("HR Settings", "HR Settings"))) + + if (allowed_role and allowed_role not in user_roles): frappe.throw(_("Only users with the {0} role can create backdated leave applications").format(allowed_role)) if self.from_date and self.to_date and (getdate(self.to_date) < getdate(self.from_date)): diff --git a/erpnext/hr/doctype/leave_application/leave_application_dashboard.py b/erpnext/hr/doctype/leave_application/leave_application_dashboard.py index c45717f5870..8b0b98ddc06 100644 --- a/erpnext/hr/doctype/leave_application/leave_application_dashboard.py +++ b/erpnext/hr/doctype/leave_application/leave_application_dashboard.py @@ -1,5 +1,3 @@ -from __future__ import unicode_literals - from frappe import _ diff --git a/erpnext/hr/doctype/leave_application/test_leave_application.py b/erpnext/hr/doctype/leave_application/test_leave_application.py index b9c785a8a9c..f73d3e52da1 100644 --- a/erpnext/hr/doctype/leave_application/test_leave_application.py +++ b/erpnext/hr/doctype/leave_application/test_leave_application.py @@ -1,6 +1,5 @@ # Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors # License: GNU General Public License v3. See license.txt -from __future__ import unicode_literals import unittest @@ -121,6 +120,7 @@ class TestLeaveApplication(unittest.TestCase): application = self.get_application(_test_records[0]) application.insert() + application.reload() application.status = "Approved" self.assertRaises(LeaveDayBlockedError, application.submit) diff --git a/erpnext/hr/doctype/leave_block_list/leave_block_list.py b/erpnext/hr/doctype/leave_block_list/leave_block_list.py index 9ba079c6e1f..d6b77f984cf 100644 --- a/erpnext/hr/doctype/leave_block_list/leave_block_list.py +++ b/erpnext/hr/doctype/leave_block_list/leave_block_list.py @@ -3,7 +3,6 @@ # For license information, please see license.txt -from __future__ import unicode_literals import frappe from frappe import _ diff --git a/erpnext/hr/doctype/leave_block_list/leave_block_list_dashboard.py b/erpnext/hr/doctype/leave_block_list/leave_block_list_dashboard.py index 30e7572c383..7cca62e0f56 100644 --- a/erpnext/hr/doctype/leave_block_list/leave_block_list_dashboard.py +++ b/erpnext/hr/doctype/leave_block_list/leave_block_list_dashboard.py @@ -1,6 +1,3 @@ -from __future__ import unicode_literals - - def get_data(): return { 'fieldname': 'leave_block_list', diff --git a/erpnext/hr/doctype/leave_block_list/test_leave_block_list.py b/erpnext/hr/doctype/leave_block_list/test_leave_block_list.py index dd90e4f9eea..afbabb66a4a 100644 --- a/erpnext/hr/doctype/leave_block_list/test_leave_block_list.py +++ b/erpnext/hr/doctype/leave_block_list/test_leave_block_list.py @@ -1,6 +1,5 @@ # Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors # License: GNU General Public License v3. See license.txt -from __future__ import unicode_literals import unittest diff --git a/erpnext/hr/doctype/leave_block_list_allow/leave_block_list_allow.py b/erpnext/hr/doctype/leave_block_list_allow/leave_block_list_allow.py index 2f648470f73..50dc125650b 100644 --- a/erpnext/hr/doctype/leave_block_list_allow/leave_block_list_allow.py +++ b/erpnext/hr/doctype/leave_block_list_allow/leave_block_list_allow.py @@ -3,7 +3,6 @@ # For license information, please see license.txt -from __future__ import unicode_literals from frappe.model.document import Document diff --git a/erpnext/hr/doctype/leave_block_list_date/leave_block_list_date.py b/erpnext/hr/doctype/leave_block_list_date/leave_block_list_date.py index 4a8f45dbcd1..36550ccd89d 100644 --- a/erpnext/hr/doctype/leave_block_list_date/leave_block_list_date.py +++ b/erpnext/hr/doctype/leave_block_list_date/leave_block_list_date.py @@ -3,7 +3,6 @@ # For license information, please see license.txt -from __future__ import unicode_literals from frappe.model.document import Document diff --git a/erpnext/hr/doctype/leave_control_panel/__init__.py b/erpnext/hr/doctype/leave_control_panel/__init__.py index baffc488252..e69de29bb2d 100644 --- a/erpnext/hr/doctype/leave_control_panel/__init__.py +++ b/erpnext/hr/doctype/leave_control_panel/__init__.py @@ -1 +0,0 @@ -from __future__ import unicode_literals diff --git a/erpnext/hr/doctype/leave_control_panel/leave_control_panel.py b/erpnext/hr/doctype/leave_control_panel/leave_control_panel.py index 681a5e27943..19f97b83d47 100644 --- a/erpnext/hr/doctype/leave_control_panel/leave_control_panel.py +++ b/erpnext/hr/doctype/leave_control_panel/leave_control_panel.py @@ -1,7 +1,6 @@ # Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors # License: GNU General Public License v3. See license.txt -from __future__ import unicode_literals import frappe from frappe import _, msgprint diff --git a/erpnext/hr/doctype/leave_control_panel/test_leave_control_panel.py b/erpnext/hr/doctype/leave_control_panel/test_leave_control_panel.py index f64b2334e86..d5a9bc04861 100644 --- a/erpnext/hr/doctype/leave_control_panel/test_leave_control_panel.py +++ b/erpnext/hr/doctype/leave_control_panel/test_leave_control_panel.py @@ -1,7 +1,5 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2018, Frappe Technologies Pvt. Ltd. and Contributors # See license.txt -from __future__ import unicode_literals import unittest diff --git a/erpnext/hr/doctype/leave_encashment/leave_encashment.py b/erpnext/hr/doctype/leave_encashment/leave_encashment.py index 7656abfa45e..8ef0e36fb8d 100644 --- a/erpnext/hr/doctype/leave_encashment/leave_encashment.py +++ b/erpnext/hr/doctype/leave_encashment/leave_encashment.py @@ -1,8 +1,6 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2018, Frappe Technologies Pvt. Ltd. and contributors # For license information, please see license.txt -from __future__ import unicode_literals import frappe from frappe import _ diff --git a/erpnext/hr/doctype/leave_encashment/test_leave_encashment.py b/erpnext/hr/doctype/leave_encashment/test_leave_encashment.py index 762745b88f4..99a479d3e5c 100644 --- a/erpnext/hr/doctype/leave_encashment/test_leave_encashment.py +++ b/erpnext/hr/doctype/leave_encashment/test_leave_encashment.py @@ -1,7 +1,5 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2018, Frappe Technologies Pvt. Ltd. and Contributors # See license.txt -from __future__ import unicode_literals import unittest diff --git a/erpnext/hr/doctype/leave_ledger_entry/leave_ledger_entry.py b/erpnext/hr/doctype/leave_ledger_entry/leave_ledger_entry.py index 6cf96851556..5c5299ea7eb 100644 --- a/erpnext/hr/doctype/leave_ledger_entry/leave_ledger_entry.py +++ b/erpnext/hr/doctype/leave_ledger_entry/leave_ledger_entry.py @@ -1,8 +1,6 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2019, Frappe Technologies Pvt. Ltd. and contributors # For license information, please see license.txt -from __future__ import unicode_literals import frappe from frappe import _ diff --git a/erpnext/hr/doctype/leave_ledger_entry/test_leave_ledger_entry.py b/erpnext/hr/doctype/leave_ledger_entry/test_leave_ledger_entry.py index 5fa419da43c..31211091831 100644 --- a/erpnext/hr/doctype/leave_ledger_entry/test_leave_ledger_entry.py +++ b/erpnext/hr/doctype/leave_ledger_entry/test_leave_ledger_entry.py @@ -1,7 +1,5 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2019, Frappe Technologies Pvt. Ltd. and Contributors # See license.txt -from __future__ import unicode_literals # import frappe import unittest diff --git a/erpnext/hr/doctype/leave_period/leave_period.py b/erpnext/hr/doctype/leave_period/leave_period.py index 143d23ab14b..b1cb6887d99 100644 --- a/erpnext/hr/doctype/leave_period/leave_period.py +++ b/erpnext/hr/doctype/leave_period/leave_period.py @@ -1,8 +1,6 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2018, Frappe Technologies Pvt. Ltd. and contributors # For license information, please see license.txt -from __future__ import unicode_literals import frappe from frappe import _ diff --git a/erpnext/hr/doctype/leave_period/leave_period_dashboard.py b/erpnext/hr/doctype/leave_period/leave_period_dashboard.py index a64c63af867..1adae0fda3f 100644 --- a/erpnext/hr/doctype/leave_period/leave_period_dashboard.py +++ b/erpnext/hr/doctype/leave_period/leave_period_dashboard.py @@ -1,5 +1,3 @@ -from __future__ import unicode_literals - from frappe import _ diff --git a/erpnext/hr/doctype/leave_period/test_leave_period.py b/erpnext/hr/doctype/leave_period/test_leave_period.py index 5c5ae133a13..10936dddc98 100644 --- a/erpnext/hr/doctype/leave_period/test_leave_period.py +++ b/erpnext/hr/doctype/leave_period/test_leave_period.py @@ -1,7 +1,5 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2018, Frappe Technologies Pvt. Ltd. and Contributors # See license.txt -from __future__ import unicode_literals import unittest diff --git a/erpnext/hr/doctype/leave_policy/leave_policy.py b/erpnext/hr/doctype/leave_policy/leave_policy.py index b11459d8155..80450d5d6e0 100644 --- a/erpnext/hr/doctype/leave_policy/leave_policy.py +++ b/erpnext/hr/doctype/leave_policy/leave_policy.py @@ -1,8 +1,6 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2018, Frappe Technologies Pvt. Ltd. and contributors # For license information, please see license.txt -from __future__ import unicode_literals import frappe from frappe import _ diff --git a/erpnext/hr/doctype/leave_policy/leave_policy_dashboard.py b/erpnext/hr/doctype/leave_policy/leave_policy_dashboard.py index 76f886c73eb..73782d6c818 100644 --- a/erpnext/hr/doctype/leave_policy/leave_policy_dashboard.py +++ b/erpnext/hr/doctype/leave_policy/leave_policy_dashboard.py @@ -1,5 +1,3 @@ -from __future__ import unicode_literals - from frappe import _ diff --git a/erpnext/hr/doctype/leave_policy/test_leave_policy.py b/erpnext/hr/doctype/leave_policy/test_leave_policy.py index b0743f535bf..3dbbef857ec 100644 --- a/erpnext/hr/doctype/leave_policy/test_leave_policy.py +++ b/erpnext/hr/doctype/leave_policy/test_leave_policy.py @@ -1,7 +1,5 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2018, Frappe Technologies Pvt. Ltd. and Contributors # See license.txt -from __future__ import unicode_literals import unittest diff --git a/erpnext/hr/doctype/leave_policy_assignment/leave_policy_assignment.py b/erpnext/hr/doctype/leave_policy_assignment/leave_policy_assignment.py index f62b3002194..dca7e4895ec 100644 --- a/erpnext/hr/doctype/leave_policy_assignment/leave_policy_assignment.py +++ b/erpnext/hr/doctype/leave_policy_assignment/leave_policy_assignment.py @@ -1,8 +1,6 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2020, Frappe Technologies Pvt. Ltd. and contributors # For license information, please see license.txt -from __future__ import unicode_literals import json from math import ceil @@ -11,7 +9,6 @@ import frappe from frappe import _, bold from frappe.model.document import Document from frappe.utils import date_diff, flt, formatdate, get_datetime, getdate -from six import string_types class LeavePolicyAssignment(Document): @@ -140,10 +137,10 @@ class LeavePolicyAssignment(Document): @frappe.whitelist() def create_assignment_for_multiple_employees(employees, data): - if isinstance(employees, string_types): + if isinstance(employees, str): employees= json.loads(employees) - if isinstance(data, string_types): + if isinstance(data, str): data = frappe._dict(json.loads(data)) docs_name = [] diff --git a/erpnext/hr/doctype/leave_policy_assignment/leave_policy_assignment_dashboard.py b/erpnext/hr/doctype/leave_policy_assignment/leave_policy_assignment_dashboard.py index 79142a63429..4363439b7ca 100644 --- a/erpnext/hr/doctype/leave_policy_assignment/leave_policy_assignment_dashboard.py +++ b/erpnext/hr/doctype/leave_policy_assignment/leave_policy_assignment_dashboard.py @@ -1,5 +1,3 @@ -from __future__ import unicode_literals - from frappe import _ diff --git a/erpnext/hr/doctype/leave_policy_assignment/test_leave_policy_assignment.py b/erpnext/hr/doctype/leave_policy_assignment/test_leave_policy_assignment.py index cbb26a1e285..b1861ad4d8e 100644 --- a/erpnext/hr/doctype/leave_policy_assignment/test_leave_policy_assignment.py +++ b/erpnext/hr/doctype/leave_policy_assignment/test_leave_policy_assignment.py @@ -1,7 +1,5 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2020, Frappe Technologies Pvt. Ltd. and Contributors # See license.txt -from __future__ import unicode_literals import unittest diff --git a/erpnext/hr/doctype/leave_policy_detail/leave_policy_detail.py b/erpnext/hr/doctype/leave_policy_detail/leave_policy_detail.py index f889424ee51..8916d3d65af 100644 --- a/erpnext/hr/doctype/leave_policy_detail/leave_policy_detail.py +++ b/erpnext/hr/doctype/leave_policy_detail/leave_policy_detail.py @@ -1,8 +1,6 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2018, Frappe Technologies Pvt. Ltd. and contributors # For license information, please see license.txt -from __future__ import unicode_literals from frappe.model.document import Document diff --git a/erpnext/hr/doctype/leave_policy_detail/test_leave_policy_detail.py b/erpnext/hr/doctype/leave_policy_detail/test_leave_policy_detail.py index 4cf9db26a2d..aacf64fd69a 100644 --- a/erpnext/hr/doctype/leave_policy_detail/test_leave_policy_detail.py +++ b/erpnext/hr/doctype/leave_policy_detail/test_leave_policy_detail.py @@ -1,7 +1,5 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2018, Frappe Technologies Pvt. Ltd. and Contributors # See license.txt -from __future__ import unicode_literals import unittest diff --git a/erpnext/hr/doctype/leave_type/__init__.py b/erpnext/hr/doctype/leave_type/__init__.py index baffc488252..e69de29bb2d 100644 --- a/erpnext/hr/doctype/leave_type/__init__.py +++ b/erpnext/hr/doctype/leave_type/__init__.py @@ -1 +0,0 @@ -from __future__ import unicode_literals diff --git a/erpnext/hr/doctype/leave_type/leave_type.js b/erpnext/hr/doctype/leave_type/leave_type.js index 8622309848a..b930dedaca8 100644 --- a/erpnext/hr/doctype/leave_type/leave_type.js +++ b/erpnext/hr/doctype/leave_type/leave_type.js @@ -2,3 +2,37 @@ frappe.ui.form.on("Leave Type", { refresh: function(frm) { } }); + + +frappe.tour["Leave Type"] = [ + { + fieldname: "max_leaves_allowed", + title: "Maximum Leave Allocation Allowed", + description: __("This field allows you to set the maximum number of leaves that can be allocated annually for this Leave Type while creating the Leave Policy") + }, + { + fieldname: "max_continuous_days_allowed", + title: "Maximum Consecutive Leaves Allowed", + description: __("This field allows you to set the maximum number of consecutive leaves an Employee can apply for.") + }, + { + fieldname: "is_optional_leave", + title: "Is Optional Leave", + description: __("Optional Leaves are holidays that Employees can choose to avail from a list of holidays published by the company.") + }, + { + fieldname: "is_compensatory", + title: "Is Compensatory Leave", + description: __("Leaves you can avail against a holiday you worked on. You can claim Compensatory Off Leave using Compensatory Leave request. Click") + " here " + __('to know more') + }, + { + fieldname: "allow_encashment", + title: "Allow Encashment", + description: __("From here, you can enable encashment for the balance leaves.") + }, + { + fieldname: "is_earned_leave", + title: "Is Earned Leaves", + description: __("Earned Leaves are leaves earned by an Employee after working with the company for a certain amount of time. Enabling this will allocate leaves on pro-rata basis by automatically updating Leave Allocation for leaves of this type at intervals set by 'Earned Leave Frequency.") + } +]; \ No newline at end of file diff --git a/erpnext/hr/doctype/leave_type/leave_type.json b/erpnext/hr/doctype/leave_type/leave_type.json index 8f2ae6eb15d..06ca4cdedbc 100644 --- a/erpnext/hr/doctype/leave_type/leave_type.json +++ b/erpnext/hr/doctype/leave_type/leave_type.json @@ -50,7 +50,7 @@ { "fieldname": "max_leaves_allowed", "fieldtype": "Int", - "label": "Max Leaves Allowed" + "label": "Maximum Leave Allocation Allowed" }, { "fieldname": "applicable_after", @@ -61,7 +61,7 @@ "fieldname": "max_continuous_days_allowed", "fieldtype": "Int", "in_list_view": 1, - "label": "Maximum Continuous Days Applicable", + "label": "Maximum Consecutive Leaves Allowed", "oldfieldname": "max_days_allowed", "oldfieldtype": "Data" }, @@ -87,6 +87,7 @@ }, { "default": "0", + "description": "These leaves are holidays permitted by the company however, availing it is optional for an Employee.", "fieldname": "is_optional_leave", "fieldtype": "Check", "label": "Is Optional Leave" @@ -205,6 +206,7 @@ }, { "depends_on": "eval:doc.is_ppl == 1", + "description": "For a day of leave taken, if you still pay (say) 50% of the daily salary, then enter 0.50 in this field.", "fieldname": "fraction_of_daily_salary_per_leave", "fieldtype": "Float", "label": "Fraction of Daily Salary per Leave", @@ -214,7 +216,7 @@ "icon": "fa fa-flag", "idx": 1, "links": [], - "modified": "2021-08-12 16:10:36.464690", + "modified": "2021-10-02 11:59:40.503359", "modified_by": "Administrator", "module": "HR", "name": "Leave Type", diff --git a/erpnext/hr/doctype/leave_type/leave_type.py b/erpnext/hr/doctype/leave_type/leave_type.py index 195c8587b97..4b59c2c09b4 100644 --- a/erpnext/hr/doctype/leave_type/leave_type.py +++ b/erpnext/hr/doctype/leave_type/leave_type.py @@ -1,7 +1,6 @@ # Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors # License: GNU General Public License v3. See license.txt -from __future__ import unicode_literals import frappe from frappe import _ diff --git a/erpnext/hr/doctype/leave_type/leave_type_dashboard.py b/erpnext/hr/doctype/leave_type/leave_type_dashboard.py index 773d4e88beb..074d3e4e52a 100644 --- a/erpnext/hr/doctype/leave_type/leave_type_dashboard.py +++ b/erpnext/hr/doctype/leave_type/leave_type_dashboard.py @@ -1,6 +1,3 @@ -from __future__ import unicode_literals - - def get_data(): return { 'fieldname': 'leave_type', diff --git a/erpnext/hr/doctype/leave_type/test_leave_type.py b/erpnext/hr/doctype/leave_type/test_leave_type.py index ee8db743f2a..c1b64e99eff 100644 --- a/erpnext/hr/doctype/leave_type/test_leave_type.py +++ b/erpnext/hr/doctype/leave_type/test_leave_type.py @@ -1,6 +1,5 @@ # Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors # License: GNU General Public License v3. See license.txt -from __future__ import unicode_literals import frappe diff --git a/erpnext/hr/doctype/offer_term/offer_term.py b/erpnext/hr/doctype/offer_term/offer_term.py index 5f8f591c97c..cee6c4518bc 100644 --- a/erpnext/hr/doctype/offer_term/offer_term.py +++ b/erpnext/hr/doctype/offer_term/offer_term.py @@ -1,7 +1,6 @@ # Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors and contributors # For license information, please see license.txt -from __future__ import unicode_literals from frappe.model.document import Document diff --git a/erpnext/hr/doctype/offer_term/test_offer_term.py b/erpnext/hr/doctype/offer_term/test_offer_term.py index ec7edd44c6f..2e5ed75438b 100644 --- a/erpnext/hr/doctype/offer_term/test_offer_term.py +++ b/erpnext/hr/doctype/offer_term/test_offer_term.py @@ -1,6 +1,5 @@ # Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors and Contributors # See license.txt -from __future__ import unicode_literals import unittest diff --git a/erpnext/hr/doctype/purpose_of_travel/purpose_of_travel.py b/erpnext/hr/doctype/purpose_of_travel/purpose_of_travel.py index f66fd276a56..c9d6e713fe1 100644 --- a/erpnext/hr/doctype/purpose_of_travel/purpose_of_travel.py +++ b/erpnext/hr/doctype/purpose_of_travel/purpose_of_travel.py @@ -1,8 +1,6 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2018, Frappe Technologies Pvt. Ltd. and contributors # For license information, please see license.txt -from __future__ import unicode_literals from frappe.model.document import Document diff --git a/erpnext/hr/doctype/purpose_of_travel/test_purpose_of_travel.py b/erpnext/hr/doctype/purpose_of_travel/test_purpose_of_travel.py index b33f389a48b..354663b78b7 100644 --- a/erpnext/hr/doctype/purpose_of_travel/test_purpose_of_travel.py +++ b/erpnext/hr/doctype/purpose_of_travel/test_purpose_of_travel.py @@ -1,7 +1,5 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2018, Frappe Technologies Pvt. Ltd. and Contributors # See license.txt -from __future__ import unicode_literals import unittest diff --git a/erpnext/hr/doctype/shift_assignment/shift_assignment.py b/erpnext/hr/doctype/shift_assignment/shift_assignment.py index 69af5c54c3b..4e829a3dbd3 100644 --- a/erpnext/hr/doctype/shift_assignment/shift_assignment.py +++ b/erpnext/hr/doctype/shift_assignment/shift_assignment.py @@ -1,8 +1,6 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2018, Frappe Technologies Pvt. Ltd. and contributors # For license information, please see license.txt -from __future__ import unicode_literals from datetime import datetime, timedelta @@ -139,7 +137,7 @@ def get_shift_type_timing(shift_types): return shift_timing_map -def get_employee_shift(employee, for_date=nowdate(), consider_default_shift=False, next_shift_direction=None): +def get_employee_shift(employee, for_date=None, consider_default_shift=False, next_shift_direction=None): """Returns a Shift Type for the given employee on the given date. (excluding the holidays) :param employee: Employee for which shift is required. @@ -147,6 +145,8 @@ def get_employee_shift(employee, for_date=nowdate(), consider_default_shift=Fals :param consider_default_shift: If set to true, default shift is taken when no shift assignment is found. :param next_shift_direction: One of: None, 'forward', 'reverse'. Direction to look for next shift if shift not found on given date. """ + if for_date is None: + for_date = nowdate() default_shift = frappe.db.get_value('Employee', employee, 'default_shift') shift_type_name = None shift_assignment_details = frappe.db.get_value('Shift Assignment', {'employee':employee, 'start_date':('<=', for_date), 'docstatus': '1', 'status': "Active"}, ['shift_type', 'end_date']) @@ -200,9 +200,11 @@ def get_employee_shift(employee, for_date=nowdate(), consider_default_shift=Fals return get_shift_details(shift_type_name, for_date) -def get_employee_shift_timings(employee, for_timestamp=now_datetime(), consider_default_shift=False): +def get_employee_shift_timings(employee, for_timestamp=None, consider_default_shift=False): """Returns previous shift, current/upcoming shift, next_shift for the given timestamp and employee """ + if for_timestamp is None: + for_timestamp = now_datetime() # write and verify a test case for midnight shift. prev_shift = curr_shift = next_shift = None curr_shift = get_employee_shift(employee, for_timestamp.date(), consider_default_shift, 'forward') @@ -220,7 +222,7 @@ def get_employee_shift_timings(employee, for_timestamp=now_datetime(), consider_ return prev_shift, curr_shift, next_shift -def get_shift_details(shift_type_name, for_date=nowdate()): +def get_shift_details(shift_type_name, for_date=None): """Returns Shift Details which contain some additional information as described below. 'shift_details' contains the following keys: 'shift_type' - Object of DocType Shift Type, @@ -234,6 +236,8 @@ def get_shift_details(shift_type_name, for_date=nowdate()): """ if not shift_type_name: return None + if not for_date: + for_date = nowdate() shift_type = frappe.get_doc('Shift Type', shift_type_name) start_datetime = datetime.combine(for_date, datetime.min.time()) + shift_type.start_time for_date = for_date + timedelta(days=1) if shift_type.start_time > shift_type.end_time else for_date diff --git a/erpnext/hr/doctype/shift_assignment/test_shift_assignment.py b/erpnext/hr/doctype/shift_assignment/test_shift_assignment.py index 84003e2ec28..d4900814ffe 100644 --- a/erpnext/hr/doctype/shift_assignment/test_shift_assignment.py +++ b/erpnext/hr/doctype/shift_assignment/test_shift_assignment.py @@ -1,7 +1,5 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2018, Frappe Technologies Pvt. Ltd. and Contributors # See license.txt -from __future__ import unicode_literals import unittest diff --git a/erpnext/hr/doctype/shift_request/shift_request.py b/erpnext/hr/doctype/shift_request/shift_request.py index a6ac7c83aeb..d4fcf99d7d8 100644 --- a/erpnext/hr/doctype/shift_request/shift_request.py +++ b/erpnext/hr/doctype/shift_request/shift_request.py @@ -1,8 +1,6 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2018, Frappe Technologies Pvt. Ltd. and contributors # For license information, please see license.txt -from __future__ import unicode_literals import frappe from frappe import _ diff --git a/erpnext/hr/doctype/shift_request/shift_request_dashboard.py b/erpnext/hr/doctype/shift_request/shift_request_dashboard.py index 3ceafc0cefe..531c98db5f8 100644 --- a/erpnext/hr/doctype/shift_request/shift_request_dashboard.py +++ b/erpnext/hr/doctype/shift_request/shift_request_dashboard.py @@ -1,6 +1,3 @@ -from __future__ import unicode_literals - - def get_data(): return { 'fieldname': 'shift_request', diff --git a/erpnext/hr/doctype/shift_request/test_shift_request.py b/erpnext/hr/doctype/shift_request/test_shift_request.py index 7b4a3ca5aab..3633c9b3003 100644 --- a/erpnext/hr/doctype/shift_request/test_shift_request.py +++ b/erpnext/hr/doctype/shift_request/test_shift_request.py @@ -1,7 +1,5 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2018, Frappe Technologies Pvt. Ltd. and Contributors # See license.txt -from __future__ import unicode_literals import unittest diff --git a/erpnext/hr/doctype/shift_type/shift_type.py b/erpnext/hr/doctype/shift_type/shift_type.py index e53373df279..562a5739d67 100644 --- a/erpnext/hr/doctype/shift_type/shift_type.py +++ b/erpnext/hr/doctype/shift_type/shift_type.py @@ -1,8 +1,6 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2018, Frappe Technologies Pvt. Ltd. and contributors # For license information, please see license.txt -from __future__ import unicode_literals import itertools from datetime import timedelta @@ -97,7 +95,7 @@ class ShiftType(Document): assigned_employees = [x[0] for x in assigned_employees] if consider_default_shift: - filters = {'default_shift': self.name} + filters = {'default_shift': self.name, 'status': ['!=', 'Inactive']} default_shift_employees = frappe.get_all('Employee', 'name', filters, as_list=True) default_shift_employees = [x[0] for x in default_shift_employees] return list(set(assigned_employees+default_shift_employees)) diff --git a/erpnext/hr/doctype/shift_type/shift_type_dashboard.py b/erpnext/hr/doctype/shift_type/shift_type_dashboard.py index b78c69a2a1e..919da2db275 100644 --- a/erpnext/hr/doctype/shift_type/shift_type_dashboard.py +++ b/erpnext/hr/doctype/shift_type/shift_type_dashboard.py @@ -1,6 +1,3 @@ -from __future__ import unicode_literals - - def get_data(): return { 'fieldname': 'shift', diff --git a/erpnext/hr/doctype/shift_type/test_shift_type.py b/erpnext/hr/doctype/shift_type/test_shift_type.py index 699030f2196..7d2f29cd6cc 100644 --- a/erpnext/hr/doctype/shift_type/test_shift_type.py +++ b/erpnext/hr/doctype/shift_type/test_shift_type.py @@ -1,7 +1,5 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2018, Frappe Technologies Pvt. Ltd. and Contributors # See license.txt -from __future__ import unicode_literals import unittest diff --git a/erpnext/hr/doctype/skill/skill.py b/erpnext/hr/doctype/skill/skill.py index ebaa410fbdd..d26e7ca4909 100644 --- a/erpnext/hr/doctype/skill/skill.py +++ b/erpnext/hr/doctype/skill/skill.py @@ -1,8 +1,6 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2019, Frappe Technologies Pvt. Ltd. and contributors # For license information, please see license.txt -from __future__ import unicode_literals # import frappe from frappe.model.document import Document diff --git a/erpnext/healthcare/doctype/dosage_form/__init__.py b/erpnext/hr/doctype/skill_assessment/__init__.py similarity index 100% rename from erpnext/healthcare/doctype/dosage_form/__init__.py rename to erpnext/hr/doctype/skill_assessment/__init__.py diff --git a/erpnext/hr/doctype/skill_assessment/skill_assessment.json b/erpnext/hr/doctype/skill_assessment/skill_assessment.json new file mode 100644 index 00000000000..8b935c4073a --- /dev/null +++ b/erpnext/hr/doctype/skill_assessment/skill_assessment.json @@ -0,0 +1,41 @@ +{ + "actions": [], + "creation": "2021-04-12 17:07:39.656289", + "doctype": "DocType", + "editable_grid": 1, + "engine": "InnoDB", + "field_order": [ + "skill", + "rating" + ], + "fields": [ + { + "fieldname": "skill", + "fieldtype": "Link", + "in_list_view": 1, + "label": "Skill", + "options": "Skill", + "read_only": 1, + "reqd": 1 + }, + { + "fieldname": "rating", + "fieldtype": "Rating", + "in_list_view": 1, + "label": "Rating", + "reqd": 1 + } + ], + "index_web_pages_for_search": 1, + "istable": 1, + "links": [], + "modified": "2021-04-12 17:18:14.032298", + "modified_by": "Administrator", + "module": "HR", + "name": "Skill Assessment", + "owner": "Administrator", + "permissions": [], + "sort_field": "modified", + "sort_order": "DESC", + "track_changes": 1 +} \ No newline at end of file diff --git a/erpnext/hr/doctype/skill_assessment/skill_assessment.py b/erpnext/hr/doctype/skill_assessment/skill_assessment.py new file mode 100644 index 00000000000..13775be6bd2 --- /dev/null +++ b/erpnext/hr/doctype/skill_assessment/skill_assessment.py @@ -0,0 +1,10 @@ +# Copyright (c) 2021, Frappe Technologies Pvt. Ltd. and contributors +# For license information, please see license.txt + + +# import frappe +from frappe.model.document import Document + + +class SkillAssessment(Document): + pass diff --git a/erpnext/hr/doctype/staffing_plan/staffing_plan.py b/erpnext/hr/doctype/staffing_plan/staffing_plan.py index 57a92b05871..7b2ea215ad8 100644 --- a/erpnext/hr/doctype/staffing_plan/staffing_plan.py +++ b/erpnext/hr/doctype/staffing_plan/staffing_plan.py @@ -1,8 +1,6 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2018, Frappe Technologies Pvt. Ltd. and contributors # For license information, please see license.txt -from __future__ import unicode_literals import frappe from frappe import _ @@ -155,7 +153,11 @@ def get_designation_counts(designation, company): return employee_counts @frappe.whitelist() -def get_active_staffing_plan_details(company, designation, from_date=getdate(nowdate()), to_date=getdate(nowdate())): +def get_active_staffing_plan_details(company, designation, from_date=None, to_date=None): + if from_date is None: + from_date = getdate(nowdate()) + if to_date is None: + to_date = getdate(nowdate()) if not company or not designation: frappe.throw(_("Please select Company and Designation")) diff --git a/erpnext/hr/doctype/staffing_plan/staffing_plan_dashboard.py b/erpnext/hr/doctype/staffing_plan/staffing_plan_dashboard.py index 24ae1223440..abde0d5a519 100644 --- a/erpnext/hr/doctype/staffing_plan/staffing_plan_dashboard.py +++ b/erpnext/hr/doctype/staffing_plan/staffing_plan_dashboard.py @@ -1,6 +1,3 @@ -from __future__ import unicode_literals - - def get_data(): return { 'fieldname': 'staffing_plan', diff --git a/erpnext/hr/doctype/staffing_plan/test_staffing_plan.py b/erpnext/hr/doctype/staffing_plan/test_staffing_plan.py index 4517cba2335..8ff0dbbc28e 100644 --- a/erpnext/hr/doctype/staffing_plan/test_staffing_plan.py +++ b/erpnext/hr/doctype/staffing_plan/test_staffing_plan.py @@ -1,7 +1,5 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2018, Frappe Technologies Pvt. Ltd. and Contributors # See license.txt -from __future__ import unicode_literals import unittest diff --git a/erpnext/hr/doctype/staffing_plan_detail/staffing_plan_detail.py b/erpnext/hr/doctype/staffing_plan_detail/staffing_plan_detail.py index ea89df3ba6e..67496909348 100644 --- a/erpnext/hr/doctype/staffing_plan_detail/staffing_plan_detail.py +++ b/erpnext/hr/doctype/staffing_plan_detail/staffing_plan_detail.py @@ -1,8 +1,6 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2018, Frappe Technologies Pvt. Ltd. and contributors # For license information, please see license.txt -from __future__ import unicode_literals from frappe.model.document import Document diff --git a/erpnext/hr/doctype/training_event/test_training_event.py b/erpnext/hr/doctype/training_event/test_training_event.py index ed44fa60704..f4329c9fe70 100644 --- a/erpnext/hr/doctype/training_event/test_training_event.py +++ b/erpnext/hr/doctype/training_event/test_training_event.py @@ -1,7 +1,5 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors # See license.txt -from __future__ import unicode_literals import unittest diff --git a/erpnext/hr/doctype/training_event/training_event.py b/erpnext/hr/doctype/training_event/training_event.py index 9b01d3d9026..c8c8bbe7339 100644 --- a/erpnext/hr/doctype/training_event/training_event.py +++ b/erpnext/hr/doctype/training_event/training_event.py @@ -1,8 +1,6 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and contributors # For license information, please see license.txt -from __future__ import unicode_literals import frappe from frappe import _ diff --git a/erpnext/hr/doctype/training_event/training_event_dashboard.py b/erpnext/hr/doctype/training_event/training_event_dashboard.py index a917c8744f7..141fffc2826 100644 --- a/erpnext/hr/doctype/training_event/training_event_dashboard.py +++ b/erpnext/hr/doctype/training_event/training_event_dashboard.py @@ -1,6 +1,3 @@ -from __future__ import unicode_literals - - def get_data(): return { 'fieldname': 'training_event', diff --git a/erpnext/hr/doctype/training_event_employee/training_event_employee.py b/erpnext/hr/doctype/training_event_employee/training_event_employee.py index 089235507a2..5dce6e17c06 100644 --- a/erpnext/hr/doctype/training_event_employee/training_event_employee.py +++ b/erpnext/hr/doctype/training_event_employee/training_event_employee.py @@ -1,8 +1,6 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and contributors # For license information, please see license.txt -from __future__ import unicode_literals from frappe.model.document import Document diff --git a/erpnext/hr/doctype/training_feedback/test_training_feedback.py b/erpnext/hr/doctype/training_feedback/test_training_feedback.py index a9bf6d6bbde..58ed6231003 100644 --- a/erpnext/hr/doctype/training_feedback/test_training_feedback.py +++ b/erpnext/hr/doctype/training_feedback/test_training_feedback.py @@ -1,7 +1,5 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors # See license.txt -from __future__ import unicode_literals import unittest diff --git a/erpnext/hr/doctype/training_feedback/training_feedback.py b/erpnext/hr/doctype/training_feedback/training_feedback.py index 6a41a657cea..1f9ec3b0b8a 100644 --- a/erpnext/hr/doctype/training_feedback/training_feedback.py +++ b/erpnext/hr/doctype/training_feedback/training_feedback.py @@ -1,8 +1,6 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and contributors # For license information, please see license.txt -from __future__ import unicode_literals import frappe from frappe import _ diff --git a/erpnext/hr/doctype/training_program/test_training_program.py b/erpnext/hr/doctype/training_program/test_training_program.py index aec319f4077..5000705ab24 100644 --- a/erpnext/hr/doctype/training_program/test_training_program.py +++ b/erpnext/hr/doctype/training_program/test_training_program.py @@ -1,7 +1,5 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2017, Frappe Technologies Pvt. Ltd. and Contributors # See license.txt -from __future__ import unicode_literals import unittest diff --git a/erpnext/hr/doctype/training_program/training_program.py b/erpnext/hr/doctype/training_program/training_program.py index 6f3ab5a806f..96b2fd70023 100644 --- a/erpnext/hr/doctype/training_program/training_program.py +++ b/erpnext/hr/doctype/training_program/training_program.py @@ -1,8 +1,6 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2017, Frappe Technologies Pvt. Ltd. and contributors # For license information, please see license.txt -from __future__ import unicode_literals from frappe.model.document import Document diff --git a/erpnext/hr/doctype/training_program/training_program_dashboard.py b/erpnext/hr/doctype/training_program/training_program_dashboard.py index b2eed6895ca..374c1e8913c 100644 --- a/erpnext/hr/doctype/training_program/training_program_dashboard.py +++ b/erpnext/hr/doctype/training_program/training_program_dashboard.py @@ -1,5 +1,3 @@ -from __future__ import unicode_literals - from frappe import _ diff --git a/erpnext/hr/doctype/training_result/test_training_result.py b/erpnext/hr/doctype/training_result/test_training_result.py index 17ccc4b4eef..1735ff4e341 100644 --- a/erpnext/hr/doctype/training_result/test_training_result.py +++ b/erpnext/hr/doctype/training_result/test_training_result.py @@ -1,7 +1,5 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors # See license.txt -from __future__ import unicode_literals import unittest diff --git a/erpnext/hr/doctype/training_result/training_result.js b/erpnext/hr/doctype/training_result/training_result.js index 5cdbcad8058..718b383e721 100644 --- a/erpnext/hr/doctype/training_result/training_result.js +++ b/erpnext/hr/doctype/training_result/training_result.js @@ -21,7 +21,7 @@ frappe.ui.form.on('Training Result', { frm.set_value("employees" ,""); if (r.message) { $.each(r.message, function(i, d) { - var row = frappe.model.add_child(cur_frm.doc, "Training Result Employee", "employees"); + var row = frappe.model.add_child(frm.doc, "Training Result Employee", "employees"); row.employee = d.employee; row.employee_name = d.employee_name; }); diff --git a/erpnext/hr/doctype/training_result/training_result.py b/erpnext/hr/doctype/training_result/training_result.py index 9cfc5707cac..bb5c71e7a15 100644 --- a/erpnext/hr/doctype/training_result/training_result.py +++ b/erpnext/hr/doctype/training_result/training_result.py @@ -1,8 +1,6 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and contributors # For license information, please see license.txt -from __future__ import unicode_literals import frappe from frappe import _ diff --git a/erpnext/hr/doctype/training_result_employee/training_result_employee.py b/erpnext/hr/doctype/training_result_employee/training_result_employee.py index b0d4605910c..e048ff53410 100644 --- a/erpnext/hr/doctype/training_result_employee/training_result_employee.py +++ b/erpnext/hr/doctype/training_result_employee/training_result_employee.py @@ -1,8 +1,6 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and contributors # For license information, please see license.txt -from __future__ import unicode_literals from frappe.model.document import Document diff --git a/erpnext/hr/doctype/travel_itinerary/travel_itinerary.py b/erpnext/hr/doctype/travel_itinerary/travel_itinerary.py index 467ef16aaee..529909b0e00 100644 --- a/erpnext/hr/doctype/travel_itinerary/travel_itinerary.py +++ b/erpnext/hr/doctype/travel_itinerary/travel_itinerary.py @@ -1,8 +1,6 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2018, Frappe Technologies Pvt. Ltd. and contributors # For license information, please see license.txt -from __future__ import unicode_literals from frappe.model.document import Document diff --git a/erpnext/hr/doctype/travel_request/test_travel_request.py b/erpnext/hr/doctype/travel_request/test_travel_request.py index 95bf8b9c8bc..e29a1ca648d 100644 --- a/erpnext/hr/doctype/travel_request/test_travel_request.py +++ b/erpnext/hr/doctype/travel_request/test_travel_request.py @@ -1,7 +1,5 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2018, Frappe Technologies Pvt. Ltd. and Contributors # See license.txt -from __future__ import unicode_literals import unittest diff --git a/erpnext/hr/doctype/travel_request/travel_request.py b/erpnext/hr/doctype/travel_request/travel_request.py index b10333fd2d6..02379c5334c 100644 --- a/erpnext/hr/doctype/travel_request/travel_request.py +++ b/erpnext/hr/doctype/travel_request/travel_request.py @@ -1,8 +1,6 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2018, Frappe Technologies Pvt. Ltd. and contributors # For license information, please see license.txt -from __future__ import unicode_literals from frappe.model.document import Document diff --git a/erpnext/hr/doctype/travel_request_costing/travel_request_costing.py b/erpnext/hr/doctype/travel_request_costing/travel_request_costing.py index 9b38d888fcb..0d1a592c80e 100644 --- a/erpnext/hr/doctype/travel_request_costing/travel_request_costing.py +++ b/erpnext/hr/doctype/travel_request_costing/travel_request_costing.py @@ -1,8 +1,6 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2018, Frappe Technologies Pvt. Ltd. and contributors # For license information, please see license.txt -from __future__ import unicode_literals from frappe.model.document import Document diff --git a/erpnext/hr/doctype/upload_attendance/test_upload_attendance.py b/erpnext/hr/doctype/upload_attendance/test_upload_attendance.py index e0a776c45d0..4c7bd805f98 100644 --- a/erpnext/hr/doctype/upload_attendance/test_upload_attendance.py +++ b/erpnext/hr/doctype/upload_attendance/test_upload_attendance.py @@ -1,7 +1,5 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors # See license.txt -from __future__ import unicode_literals import unittest diff --git a/erpnext/hr/doctype/upload_attendance/upload_attendance.py b/erpnext/hr/doctype/upload_attendance/upload_attendance.py index 030ecec74f9..94eb3001009 100644 --- a/erpnext/hr/doctype/upload_attendance/upload_attendance.py +++ b/erpnext/hr/doctype/upload_attendance/upload_attendance.py @@ -3,7 +3,6 @@ # For license information, please see license.txt -from __future__ import unicode_literals import frappe from frappe import _ diff --git a/erpnext/hr/doctype/vehicle/test_vehicle.py b/erpnext/hr/doctype/vehicle/test_vehicle.py index 2bc94c65090..c5ea5a38c86 100644 --- a/erpnext/hr/doctype/vehicle/test_vehicle.py +++ b/erpnext/hr/doctype/vehicle/test_vehicle.py @@ -1,7 +1,5 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors # See license.txt -from __future__ import unicode_literals import unittest diff --git a/erpnext/hr/doctype/vehicle/vehicle.py b/erpnext/hr/doctype/vehicle/vehicle.py index 2ff190426dd..946233b5481 100644 --- a/erpnext/hr/doctype/vehicle/vehicle.py +++ b/erpnext/hr/doctype/vehicle/vehicle.py @@ -1,8 +1,6 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and contributors # For license information, please see license.txt -from __future__ import unicode_literals import frappe from frappe import _ diff --git a/erpnext/hr/doctype/vehicle/vehicle_dashboard.py b/erpnext/hr/doctype/vehicle/vehicle_dashboard.py index 6a01bcffd50..f6e5f06d8cb 100644 --- a/erpnext/hr/doctype/vehicle/vehicle_dashboard.py +++ b/erpnext/hr/doctype/vehicle/vehicle_dashboard.py @@ -1,5 +1,3 @@ -from __future__ import unicode_literals - from frappe import _ diff --git a/erpnext/hr/doctype/vehicle_log/test_vehicle_log.py b/erpnext/hr/doctype/vehicle_log/test_vehicle_log.py index 1b0bfcb08f9..acd50f278cd 100644 --- a/erpnext/hr/doctype/vehicle_log/test_vehicle_log.py +++ b/erpnext/hr/doctype/vehicle_log/test_vehicle_log.py @@ -1,7 +1,5 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors # See license.txt -from __future__ import unicode_literals import unittest diff --git a/erpnext/hr/doctype/vehicle_log/vehicle_log.py b/erpnext/hr/doctype/vehicle_log/vehicle_log.py index 73c848b0346..e414141efb5 100644 --- a/erpnext/hr/doctype/vehicle_log/vehicle_log.py +++ b/erpnext/hr/doctype/vehicle_log/vehicle_log.py @@ -1,8 +1,6 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and contributors # For license information, please see license.txt -from __future__ import unicode_literals import frappe from frappe import _ diff --git a/erpnext/hr/doctype/vehicle_service/vehicle_service.py b/erpnext/hr/doctype/vehicle_service/vehicle_service.py index bc93a97481d..fdd4e39dd85 100644 --- a/erpnext/hr/doctype/vehicle_service/vehicle_service.py +++ b/erpnext/hr/doctype/vehicle_service/vehicle_service.py @@ -1,8 +1,6 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and contributors # For license information, please see license.txt -from __future__ import unicode_literals from frappe.model.document import Document diff --git a/erpnext/hr/module_onboarding/human_resource/human_resource.json b/erpnext/hr/module_onboarding/human_resource/human_resource.json index 518c002bcaa..cd11bd1102e 100644 --- a/erpnext/hr/module_onboarding/human_resource/human_resource.json +++ b/erpnext/hr/module_onboarding/human_resource/human_resource.json @@ -13,17 +13,14 @@ "documentation_url": "https://docs.erpnext.com/docs/user/manual/en/human-resources", "idx": 0, "is_complete": 0, - "modified": "2020-07-08 14:05:47.018799", + "modified": "2021-05-19 05:32:01.794628", "modified_by": "Administrator", "module": "HR", "name": "Human Resource", "owner": "Administrator", "steps": [ { - "step": "Create Department" - }, - { - "step": "Create Designation" + "step": "HR Settings" }, { "step": "Create Holiday list" @@ -31,6 +28,9 @@ { "step": "Create Employee" }, + { + "step": "Data import" + }, { "step": "Create Leave Type" }, @@ -39,9 +39,6 @@ }, { "step": "Create Leave Application" - }, - { - "step": "HR Settings" } ], "subtitle": "Employee, Leaves, and more.", diff --git a/erpnext/hr/notification/training_feedback/training_feedback.py b/erpnext/hr/notification/training_feedback/training_feedback.py index f57de916dd1..02e3e933330 100644 --- a/erpnext/hr/notification/training_feedback/training_feedback.py +++ b/erpnext/hr/notification/training_feedback/training_feedback.py @@ -1,6 +1,3 @@ -from __future__ import unicode_literals - - def get_context(context): # do your magic here pass diff --git a/erpnext/hr/notification/training_scheduled/training_scheduled.py b/erpnext/hr/notification/training_scheduled/training_scheduled.py index f57de916dd1..02e3e933330 100644 --- a/erpnext/hr/notification/training_scheduled/training_scheduled.py +++ b/erpnext/hr/notification/training_scheduled/training_scheduled.py @@ -1,6 +1,3 @@ -from __future__ import unicode_literals - - def get_context(context): # do your magic here pass diff --git a/erpnext/hr/onboarding_step/create_employee/create_employee.json b/erpnext/hr/onboarding_step/create_employee/create_employee.json index 3aa33c6d862..47828186bf3 100644 --- a/erpnext/hr/onboarding_step/create_employee/create_employee.json +++ b/erpnext/hr/onboarding_step/create_employee/create_employee.json @@ -1,18 +1,20 @@ { - "action": "Create Entry", + "action": "Show Form Tour", + "action_label": "Show Tour", "creation": "2020-05-14 11:43:25.561152", + "description": "

Employee

\n\nAn individual who works and is recognized for his rights and duties in your company is your Employee. You can manage the Employee master. It captures the demographic, personal and professional details, joining and leave details, etc.", "docstatus": 0, "doctype": "Onboarding Step", "idx": 0, "is_complete": 0, - "is_mandatory": 1, "is_single": 0, "is_skipped": 0, - "modified": "2020-05-14 12:26:28.629074", + "modified": "2021-05-19 04:50:02.240321", "modified_by": "Administrator", "name": "Create Employee", "owner": "Administrator", "reference_document": "Employee", + "show_form_tour": 0, "show_full_form": 0, "title": "Create Employee", "validate_action": 0 diff --git a/erpnext/hr/onboarding_step/create_holiday_list/create_holiday_list.json b/erpnext/hr/onboarding_step/create_holiday_list/create_holiday_list.json index 32472b4b3fa..a08e85fff01 100644 --- a/erpnext/hr/onboarding_step/create_holiday_list/create_holiday_list.json +++ b/erpnext/hr/onboarding_step/create_holiday_list/create_holiday_list.json @@ -1,18 +1,20 @@ { - "action": "Create Entry", + "action": "Show Form Tour", + "action_label": "Show Tour", "creation": "2020-05-28 11:47:34.700174", + "description": "

Holiday List.

\n\nHoliday List is a list which contains the dates of holidays. Most organizations have a standard Holiday List for their employees. However, some of them may have different holiday lists based on different Locations or Departments. In ERPNext, you can configure multiple Holiday Lists.", "docstatus": 0, "doctype": "Onboarding Step", "idx": 0, "is_complete": 0, - "is_mandatory": 1, "is_single": 0, "is_skipped": 0, - "modified": "2020-05-14 12:25:38.068582", + "modified": "2021-05-19 04:19:52.305199", "modified_by": "Administrator", "name": "Create Holiday list", "owner": "Administrator", "reference_document": "Holiday List", + "show_form_tour": 0, "show_full_form": 1, "title": "Create Holiday List", "validate_action": 0 diff --git a/erpnext/hr/onboarding_step/create_leave_allocation/create_leave_allocation.json b/erpnext/hr/onboarding_step/create_leave_allocation/create_leave_allocation.json index fa9941e6b97..0b0ce3fc8bb 100644 --- a/erpnext/hr/onboarding_step/create_leave_allocation/create_leave_allocation.json +++ b/erpnext/hr/onboarding_step/create_leave_allocation/create_leave_allocation.json @@ -1,18 +1,20 @@ { - "action": "Create Entry", + "action": "Show Form Tour", + "action_label": "Show Tour", "creation": "2020-05-14 11:48:56.123718", + "description": "

Leave Allocation

\n\nLeave Allocation enables you to allocate a specific number of leaves of a particular type to an Employee so that, an employee will be able to create a Leave Application only if Leaves are allocated. ", "docstatus": 0, "doctype": "Onboarding Step", "idx": 0, "is_complete": 0, - "is_mandatory": 1, "is_single": 0, "is_skipped": 0, - "modified": "2020-05-14 11:48:56.123718", + "modified": "2021-05-19 04:22:34.220238", "modified_by": "Administrator", "name": "Create Leave Allocation", "owner": "Administrator", "reference_document": "Leave Allocation", + "show_form_tour": 0, "show_full_form": 0, "title": "Create Leave Allocation", "validate_action": 0 diff --git a/erpnext/hr/onboarding_step/create_leave_application/create_leave_application.json b/erpnext/hr/onboarding_step/create_leave_application/create_leave_application.json index 1ed074e9a1d..af63aa59ed6 100644 --- a/erpnext/hr/onboarding_step/create_leave_application/create_leave_application.json +++ b/erpnext/hr/onboarding_step/create_leave_application/create_leave_application.json @@ -1,18 +1,20 @@ { - "action": "Create Entry", + "action": "Show Form Tour", + "action_label": "Show Tour", "creation": "2020-05-14 11:49:45.400764", + "description": "

Leave Application

\n\nLeave Application is a formal document created by an Employee to apply for Leaves for a particular time period based on there leave allocation and leave type according to there need.", "docstatus": 0, "doctype": "Onboarding Step", "idx": 0, "is_complete": 0, - "is_mandatory": 1, "is_single": 0, "is_skipped": 0, - "modified": "2020-05-14 11:49:45.400764", + "modified": "2021-05-19 04:39:09.893474", "modified_by": "Administrator", "name": "Create Leave Application", "owner": "Administrator", "reference_document": "Leave Application", + "show_form_tour": 0, "show_full_form": 0, "title": "Create Leave Application", "validate_action": 0 diff --git a/erpnext/hr/onboarding_step/create_leave_type/create_leave_type.json b/erpnext/hr/onboarding_step/create_leave_type/create_leave_type.json index 8cbfc5c81f9..397f5cde49c 100644 --- a/erpnext/hr/onboarding_step/create_leave_type/create_leave_type.json +++ b/erpnext/hr/onboarding_step/create_leave_type/create_leave_type.json @@ -1,18 +1,20 @@ { - "action": "Create Entry", + "action": "Show Form Tour", + "action_label": "Show Tour", "creation": "2020-05-27 11:17:31.119312", + "description": "

Leave Type

\n\nLeave type is defined based on many factors and features like encashment, earned leaves, partially paid, without pay and, a lot more. To check other options and to define your leave type click on Show Tour.", "docstatus": 0, "doctype": "Onboarding Step", "idx": 0, "is_complete": 0, - "is_mandatory": 1, "is_single": 0, "is_skipped": 0, - "modified": "2020-05-20 11:17:31.119312", + "modified": "2021-05-19 04:32:48.135406", "modified_by": "Administrator", "name": "Create Leave Type", "owner": "Administrator", "reference_document": "Leave Type", + "show_form_tour": 0, "show_full_form": 1, "title": "Create Leave Type", "validate_action": 0 diff --git a/erpnext/hr/onboarding_step/data_import/data_import.json b/erpnext/hr/onboarding_step/data_import/data_import.json new file mode 100644 index 00000000000..ac343c67759 --- /dev/null +++ b/erpnext/hr/onboarding_step/data_import/data_import.json @@ -0,0 +1,21 @@ +{ + "action": "Watch Video", + "action_label": "", + "creation": "2021-05-19 05:29:16.809610", + "description": "

Data Import

\n\nData import is the tool to migrate your existing data like Employee, Customer, Supplier, and a lot more to our ERPNext system.\nGo through the video for a detailed explanation of this tool.", + "docstatus": 0, + "doctype": "Onboarding Step", + "idx": 0, + "is_complete": 0, + "is_single": 0, + "is_skipped": 0, + "modified": "2021-05-19 05:29:16.809610", + "modified_by": "Administrator", + "name": "Data import", + "owner": "Administrator", + "show_form_tour": 0, + "show_full_form": 0, + "title": "Data Import", + "validate_action": 1, + "video_url": "https://www.youtube.com/watch?v=DQyqeurPI64" +} \ No newline at end of file diff --git a/erpnext/hr/onboarding_step/hr_settings/hr_settings.json b/erpnext/hr/onboarding_step/hr_settings/hr_settings.json index 0a1d0baf8aa..355664fbc59 100644 --- a/erpnext/hr/onboarding_step/hr_settings/hr_settings.json +++ b/erpnext/hr/onboarding_step/hr_settings/hr_settings.json @@ -1,18 +1,20 @@ { - "action": "Update Settings", + "action": "Show Form Tour", + "action_label": "Explore", "creation": "2020-05-28 13:13:52.427711", + "description": "

HR Settings

\n\nHr Settings consists of major settings related to Employee Lifecycle, Leave Management, etc. Click on Explore, to explore Hr Settings.", "docstatus": 0, "doctype": "Onboarding Step", "idx": 0, "is_complete": 0, - "is_mandatory": 0, "is_single": 1, "is_skipped": 0, - "modified": "2020-05-20 11:16:42.430974", + "modified": "2021-05-18 07:02:05.747548", "modified_by": "Administrator", "name": "HR Settings", "owner": "Administrator", "reference_document": "HR Settings", + "show_form_tour": 0, "show_full_form": 0, "title": "HR Settings", "validate_action": 0 diff --git a/erpnext/hr/page/__init__.py b/erpnext/hr/page/__init__.py index baffc488252..e69de29bb2d 100644 --- a/erpnext/hr/page/__init__.py +++ b/erpnext/hr/page/__init__.py @@ -1 +0,0 @@ -from __future__ import unicode_literals diff --git a/erpnext/hr/page/organizational_chart/organizational_chart.py b/erpnext/hr/page/organizational_chart/organizational_chart.py index 1baf805f4b9..1e2d7581795 100644 --- a/erpnext/hr/page/organizational_chart/organizational_chart.py +++ b/erpnext/hr/page/organizational_chart/organizational_chart.py @@ -1,5 +1,3 @@ -from __future__ import unicode_literals - import frappe diff --git a/erpnext/hr/page/team_updates/team_updates.py b/erpnext/hr/page/team_updates/team_updates.py index a5e7c44c31d..0a4624c531e 100644 --- a/erpnext/hr/page/team_updates/team_updates.py +++ b/erpnext/hr/page/team_updates/team_updates.py @@ -1,5 +1,3 @@ -from __future__ import unicode_literals - import frappe from email_reply_parser import EmailReplyParser diff --git a/erpnext/hr/report/daily_work_summary_replies/daily_work_summary_replies.py b/erpnext/hr/report/daily_work_summary_replies/daily_work_summary_replies.py index 62ffb7d3445..63764bb8a9c 100644 --- a/erpnext/hr/report/daily_work_summary_replies/daily_work_summary_replies.py +++ b/erpnext/hr/report/daily_work_summary_replies/daily_work_summary_replies.py @@ -1,7 +1,6 @@ # Copyright (c) 2013, Frappe Technologies Pvt. Ltd. and contributors # For license information, please see license.txt -from __future__ import unicode_literals import frappe from frappe import _ diff --git a/erpnext/hr/report/employee_advance_summary/employee_advance_summary.py b/erpnext/hr/report/employee_advance_summary/employee_advance_summary.py index d0c295df9f1..62b83f26a61 100644 --- a/erpnext/hr/report/employee_advance_summary/employee_advance_summary.py +++ b/erpnext/hr/report/employee_advance_summary/employee_advance_summary.py @@ -1,7 +1,6 @@ # Copyright (c) 2013, Frappe Technologies Pvt. Ltd. and contributors # For license information, please see license.txt -from __future__ import unicode_literals import frappe from frappe import _, msgprint diff --git a/erpnext/hr/report/employee_analytics/employee_analytics.py b/erpnext/hr/report/employee_analytics/employee_analytics.py index 725c5a15713..3a75276cb07 100644 --- a/erpnext/hr/report/employee_analytics/employee_analytics.py +++ b/erpnext/hr/report/employee_analytics/employee_analytics.py @@ -1,7 +1,6 @@ # Copyright (c) 2013, Frappe Technologies Pvt. Ltd. and contributors # For license information, please see license.txt -from __future__ import unicode_literals import frappe from frappe import _ diff --git a/erpnext/hr/report/employee_birthday/employee_birthday.py b/erpnext/hr/report/employee_birthday/employee_birthday.py index b284e6babe6..cec5a48c199 100644 --- a/erpnext/hr/report/employee_birthday/employee_birthday.py +++ b/erpnext/hr/report/employee_birthday/employee_birthday.py @@ -1,7 +1,6 @@ # Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors # License: GNU General Public License v3. See license.txt -from __future__ import unicode_literals import frappe from frappe import _ diff --git a/erpnext/hr/report/employee_leave_balance/employee_leave_balance.py b/erpnext/hr/report/employee_leave_balance/employee_leave_balance.py index 6bca1368d3f..b375b18b079 100644 --- a/erpnext/hr/report/employee_leave_balance/employee_leave_balance.py +++ b/erpnext/hr/report/employee_leave_balance/employee_leave_balance.py @@ -1,7 +1,6 @@ # Copyright (c) 2013, Frappe Technologies Pvt. Ltd. and contributors # For license information, please see license.txt -from __future__ import unicode_literals from itertools import groupby @@ -182,10 +181,11 @@ def get_allocated_and_expired_leaves(from_date, to_date, employee, leave_type): records= frappe.db.sql(""" SELECT employee, leave_type, from_date, to_date, leaves, transaction_name, - is_carry_forward, is_expired + transaction_type, is_carry_forward, is_expired FROM `tabLeave Ledger Entry` WHERE employee=%(employee)s AND leave_type=%(leave_type)s AND docstatus=1 + AND transaction_type = 'Leave Allocation' AND (from_date between %(from_date)s AND %(to_date)s OR to_date between %(from_date)s AND %(to_date)s OR (from_date < %(from_date)s AND to_date > %(to_date)s)) diff --git a/erpnext/hr/report/employee_leave_balance_summary/employee_leave_balance_summary.py b/erpnext/hr/report/employee_leave_balance_summary/employee_leave_balance_summary.py index bcbb066d9f1..71c18bb51ff 100644 --- a/erpnext/hr/report/employee_leave_balance_summary/employee_leave_balance_summary.py +++ b/erpnext/hr/report/employee_leave_balance_summary/employee_leave_balance_summary.py @@ -1,7 +1,6 @@ # Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors # License: GNU General Public License v3. See license.txt -from __future__ import unicode_literals import frappe from frappe import _ diff --git a/erpnext/hr/report/employees_working_on_a_holiday/employees_working_on_a_holiday.py b/erpnext/hr/report/employees_working_on_a_holiday/employees_working_on_a_holiday.py index 3a268821361..00a4a7c29f5 100644 --- a/erpnext/hr/report/employees_working_on_a_holiday/employees_working_on_a_holiday.py +++ b/erpnext/hr/report/employees_working_on_a_holiday/employees_working_on_a_holiday.py @@ -1,7 +1,6 @@ # Copyright (c) 2013, Frappe Technologies Pvt. Ltd. and contributors # For license information, please see license.txt -from __future__ import unicode_literals import frappe from frappe import _ diff --git a/erpnext/hr/report/monthly_attendance_sheet/monthly_attendance_sheet.py b/erpnext/hr/report/monthly_attendance_sheet/monthly_attendance_sheet.py index c6e6432d200..9a993e52e27 100644 --- a/erpnext/hr/report/monthly_attendance_sheet/monthly_attendance_sheet.py +++ b/erpnext/hr/report/monthly_attendance_sheet/monthly_attendance_sheet.py @@ -1,7 +1,6 @@ # Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors # License: GNU General Public License v3. See license.txt -from __future__ import unicode_literals from calendar import monthrange diff --git a/erpnext/hr/report/recruitment_analytics/recruitment_analytics.py b/erpnext/hr/report/recruitment_analytics/recruitment_analytics.py index c598e9e3730..6383a9bbac9 100644 --- a/erpnext/hr/report/recruitment_analytics/recruitment_analytics.py +++ b/erpnext/hr/report/recruitment_analytics/recruitment_analytics.py @@ -1,7 +1,6 @@ # Copyright (c) 2013, Frappe Technologies Pvt. Ltd. and contributors # For license information, please see license.txt -from __future__ import unicode_literals import frappe from frappe import _ diff --git a/erpnext/hr/report/vehicle_expenses/test_vehicle_expenses.py b/erpnext/hr/report/vehicle_expenses/test_vehicle_expenses.py index 2ba87efd9b2..8672e68cf4b 100644 --- a/erpnext/hr/report/vehicle_expenses/test_vehicle_expenses.py +++ b/erpnext/hr/report/vehicle_expenses/test_vehicle_expenses.py @@ -1,7 +1,6 @@ # Copyright (c) 2018, Frappe Technologies Pvt. Ltd. and Contributors # License: GNU General Public License v3. See license.txt -from __future__ import unicode_literals import unittest diff --git a/erpnext/hr/report/vehicle_expenses/vehicle_expenses.py b/erpnext/hr/report/vehicle_expenses/vehicle_expenses.py index 2be3565a059..17d1e9d46a0 100644 --- a/erpnext/hr/report/vehicle_expenses/vehicle_expenses.py +++ b/erpnext/hr/report/vehicle_expenses/vehicle_expenses.py @@ -1,7 +1,6 @@ # Copyright (c) 2013, Frappe Technologies Pvt. Ltd. and contributors # For license information, please see license.txt -from __future__ import unicode_literals import frappe from frappe import _ diff --git a/erpnext/hr/utils.py b/erpnext/hr/utils.py index deec6442093..0febce1610a 100644 --- a/erpnext/hr/utils.py +++ b/erpnext/hr/utils.py @@ -29,10 +29,21 @@ def set_employee_name(doc): if doc.employee and not doc.employee_name: doc.employee_name = frappe.db.get_value("Employee", doc.employee, "employee_name") -def update_employee(employee, details, date=None, cancel=False): +def update_employee_work_history(employee, details, date=None, cancel=False): + if not employee.internal_work_history and not cancel: + employee.append("internal_work_history", { + "branch": employee.branch, + "designation": employee.designation, + "department": employee.department, + "from_date": employee.date_of_joining + }) + internal_work_history = {} for item in details: - fieldtype = frappe.get_meta("Employee").get_field(item.fieldname).fieldtype + field = frappe.get_meta("Employee").get_field(item.fieldname) + if not field: + continue + fieldtype = field.fieldtype new_data = item.new if not cancel else item.current if fieldtype == "Date" and new_data: new_data = getdate(new_data) @@ -41,11 +52,35 @@ def update_employee(employee, details, date=None, cancel=False): setattr(employee, item.fieldname, new_data) if item.fieldname in ["department", "designation", "branch"]: internal_work_history[item.fieldname] = item.new + if internal_work_history and not cancel: internal_work_history["from_date"] = date employee.append("internal_work_history", internal_work_history) + + if cancel: + delete_employee_work_history(details, employee, date) + return employee +def delete_employee_work_history(details, employee, date): + filters = {} + for d in details: + for history in employee.internal_work_history: + if d.property == "Department" and history.department == d.new: + department = d.new + filters["department"] = department + if d.property == "Designation" and history.designation == d.new: + designation = d.new + filters["designation"] = designation + if d.property == "Branch" and history.branch == d.new: + branch = d.new + filters["branch"] = branch + if date and date == history.from_date: + filters["from_date"] = date + if filters: + frappe.db.delete("Employee Internal Work History", filters) + + @frappe.whitelist() def get_employee_fields_label(): fields = [] diff --git a/erpnext/hr/web_form/job_application/job_application.py b/erpnext/hr/web_form/job_application/job_application.py index f57de916dd1..02e3e933330 100644 --- a/erpnext/hr/web_form/job_application/job_application.py +++ b/erpnext/hr/web_form/job_application/job_application.py @@ -1,6 +1,3 @@ -from __future__ import unicode_literals - - def get_context(context): # do your magic here pass diff --git a/erpnext/hr/workspace/hr/hr.json b/erpnext/hr/workspace/hr/hr.json index 9c5d0c1b0ec..7408d63eee5 100644 --- a/erpnext/hr/workspace/hr/hr.json +++ b/erpnext/hr/workspace/hr/hr.json @@ -1,5 +1,4 @@ { - "category": "", "charts": [ { "chart_name": "Outgoing Salary", @@ -8,18 +7,12 @@ ], "content": "[{\"type\": \"onboarding\", \"data\": {\"onboarding_name\":\"Human Resource\", \"col\": 12}}, {\"type\": \"chart\", \"data\": {\"chart_name\": \"Outgoing Salary\", \"col\": 12}}, {\"type\": \"spacer\", \"data\": {\"col\": 12}}, {\"type\": \"header\", \"data\": {\"text\": \"Your Shortcuts\", \"level\": 4, \"col\": 12}}, {\"type\": \"shortcut\", \"data\": {\"shortcut_name\": \"Employee\", \"col\": 4}}, {\"type\": \"shortcut\", \"data\": {\"shortcut_name\": \"Leave Application\", \"col\": 4}}, {\"type\": \"shortcut\", \"data\": {\"shortcut_name\": \"Attendance\", \"col\": 4}}, {\"type\": \"shortcut\", \"data\": {\"shortcut_name\": \"Job Applicant\", \"col\": 4}}, {\"type\": \"shortcut\", \"data\": {\"shortcut_name\": \"Monthly Attendance Sheet\", \"col\": 4}}, {\"type\": \"shortcut\", \"data\": {\"shortcut_name\": \"Dashboard\", \"col\": 4}}, {\"type\": \"spacer\", \"data\": {\"col\": 12}}, {\"type\": \"header\", \"data\": {\"text\": \"Reports & Masters\", \"level\": 4, \"col\": 12}}, {\"type\": \"card\", \"data\": {\"card_name\": \"Employee\", \"col\": 4}}, {\"type\": \"card\", \"data\": {\"card_name\": \"Employee Lifecycle\", \"col\": 4}}, {\"type\": \"card\", \"data\": {\"card_name\": \"Shift Management\", \"col\": 4}}, {\"type\": \"card\", \"data\": {\"card_name\": \"Leaves\", \"col\": 4}}, {\"type\": \"card\", \"data\": {\"card_name\": \"Attendance\", \"col\": 4}}, {\"type\": \"card\", \"data\": {\"card_name\": \"Expense Claims\", \"col\": 4}}, {\"type\": \"card\", \"data\": {\"card_name\": \"Settings\", \"col\": 4}}, {\"type\": \"card\", \"data\": {\"card_name\": \"Fleet Management\", \"col\": 4}}, {\"type\": \"card\", \"data\": {\"card_name\": \"Recruitment\", \"col\": 4}}, {\"type\": \"card\", \"data\": {\"card_name\": \"Loans\", \"col\": 4}}, {\"type\": \"card\", \"data\": {\"card_name\": \"Training\", \"col\": 4}}, {\"type\": \"card\", \"data\": {\"card_name\": \"Performance\", \"col\": 4}}, {\"type\": \"card\", \"data\": {\"card_name\": \"Key Reports\", \"col\": 4}}, {\"type\": \"card\", \"data\": {\"card_name\": \"Other Reports\", \"col\": 4}}]", "creation": "2020-03-02 15:48:58.322521", - "developer_mode_only": 0, - "disable_user_customization": 0, "docstatus": 0, "doctype": "Workspace", - "extends": "", - "extends_another_page": 0, "for_user": "", "hide_custom": 0, "icon": "hr", "idx": 0, - "is_default": 0, - "is_standard": 0, "label": "HR", "links": [ { @@ -942,15 +935,12 @@ "type": "Link" } ], - "modified": "2021-08-31 12:18:59.842918", + "modified": "2021-08-31 12:18:59.842919", "modified_by": "Administrator", "module": "HR", "name": "HR", - "onboarding": "Human Resource", "owner": "Administrator", "parent_page": "", - "pin_to_bottom": 0, - "pin_to_top": 0, "public": 1, "restrict_to_domain": "", "roles": [], diff --git a/erpnext/hub/__init__.py b/erpnext/hub/__init__.py deleted file mode 100644 index e69de29bb2d..00000000000 diff --git a/erpnext/hub_node/__init__.py b/erpnext/hub_node/__init__.py deleted file mode 100644 index 6ac3255c12a..00000000000 --- a/erpnext/hub_node/__init__.py +++ /dev/null @@ -1,19 +0,0 @@ -# Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors and contributors -# For license information, please see license.txt - -from __future__ import unicode_literals - -import frappe - - -@frappe.whitelist() -def enable_hub(): - hub_settings = frappe.get_doc('Marketplace Settings') - hub_settings.register() - frappe.db.commit() - return hub_settings - -@frappe.whitelist() -def sync(): - hub_settings = frappe.get_doc('Marketplace Settings') - hub_settings.sync() diff --git a/erpnext/hub_node/api.py b/erpnext/hub_node/api.py deleted file mode 100644 index 55304917759..00000000000 --- a/erpnext/hub_node/api.py +++ /dev/null @@ -1,233 +0,0 @@ -from __future__ import unicode_literals - -import json - -import frappe -from frappe import _ -from frappe.desk.form.load import get_attachments -from frappe.frappeclient import FrappeClient -from six import string_types - -current_user = frappe.session.user - - -@frappe.whitelist() -def register_marketplace(company, company_description): - validate_registerer() - - settings = frappe.get_single('Marketplace Settings') - message = settings.register_seller(company, company_description) - - if message.get('hub_seller_name'): - settings.registered = 1 - settings.hub_seller_name = message.get('hub_seller_name') - settings.save() - - settings.add_hub_user(frappe.session.user) - - return { 'ok': 1 } - - -@frappe.whitelist() -def register_users(user_list): - user_list = json.loads(user_list) - - settings = frappe.get_single('Marketplace Settings') - - for user in user_list: - settings.add_hub_user(user) - - return user_list - - -def validate_registerer(): - if current_user == 'Administrator': - frappe.throw(_('Please login as another user to register on Marketplace')) - - valid_roles = ['System Manager', 'Item Manager'] - - if not frappe.utils.is_subset(valid_roles, frappe.get_roles()): - frappe.throw(_('Only users with {0} role can register on Marketplace').format(', '.join(valid_roles)), - frappe.PermissionError) - - -@frappe.whitelist() -def call_hub_method(method, params=None): - connection = get_hub_connection() - - if isinstance(params, string_types): - params = json.loads(params) - - params.update({ - 'cmd': 'hub.hub.api.' + method - }) - - response = connection.post_request(params) - return response - - -def map_fields(items): - field_mappings = get_field_mappings() - table_fields = [d.fieldname for d in frappe.get_meta('Item').get_table_fields()] - - hub_seller_name = frappe.db.get_value('Marketplace Settings', 'Marketplace Settings', 'hub_seller_name') - - for item in items: - for fieldname in table_fields: - item.pop(fieldname, None) - - for mapping in field_mappings: - local_fieldname = mapping.get('local_fieldname') - remote_fieldname = mapping.get('remote_fieldname') - - value = item.get(local_fieldname) - item.pop(local_fieldname, None) - item[remote_fieldname] = value - - item['doctype'] = 'Hub Item' - item['hub_seller'] = hub_seller_name - item.pop('attachments', None) - - return items - - -@frappe.whitelist() -def get_valid_items(search_value=''): - items = frappe.get_list( - 'Item', - fields=["*"], - filters={ - 'disabled': 0, - 'item_name': ['like', '%' + search_value + '%'], - 'publish_in_hub': 0 - }, - order_by="modified desc" - ) - - valid_items = filter(lambda x: x.image and x.description, items) - - def prepare_item(item): - item.source_type = "local" - item.attachments = get_attachments('Item', item.item_code) - return item - - valid_items = map(prepare_item, valid_items) - - return valid_items - -@frappe.whitelist() -def update_item(ref_doc, data): - data = json.loads(data) - - data.update(dict(doctype='Hub Item', name=ref_doc)) - try: - connection = get_hub_connection() - connection.update(data) - except Exception as e: - frappe.log_error(message=e, title='Hub Sync Error') - -@frappe.whitelist() -def publish_selected_items(items_to_publish): - items_to_publish = json.loads(items_to_publish) - items_to_update = [] - if not len(items_to_publish): - frappe.throw(_('No items to publish')) - - for item in items_to_publish: - item_code = item.get('item_code') - frappe.db.set_value('Item', item_code, 'publish_in_hub', 1) - - hub_dict = { - 'doctype': 'Hub Tracked Item', - 'item_code': item_code, - 'published': 1, - 'hub_category': item.get('hub_category'), - 'image_list': item.get('image_list') - } - frappe.get_doc(hub_dict).insert(ignore_if_duplicate=True) - - items = map_fields(items_to_publish) - - try: - item_sync_preprocess(len(items)) - convert_relative_image_urls_to_absolute(items) - - # TODO: Publish Progress - connection = get_hub_connection() - connection.insert_many(items) - - item_sync_postprocess() - except Exception as e: - frappe.log_error(message=e, title='Hub Sync Error') - -@frappe.whitelist() -def unpublish_item(item_code, hub_item_name): - ''' Remove item listing from the marketplace ''' - - response = call_hub_method('unpublish_item', { - 'hub_item_name': hub_item_name - }) - - if response: - frappe.db.set_value('Item', item_code, 'publish_in_hub', 0) - frappe.delete_doc('Hub Tracked Item', item_code) - else: - frappe.throw(_('Unable to update remote activity')) - -@frappe.whitelist() -def get_unregistered_users(): - settings = frappe.get_single('Marketplace Settings') - registered_users = [user.user for user in settings.users] + ['Administrator', 'Guest'] - all_users = [user.name for user in frappe.db.get_all('User', filters={'enabled': 1})] - unregistered_users = [user for user in all_users if user not in registered_users] - return unregistered_users - - -def item_sync_preprocess(intended_item_publish_count): - response = call_hub_method('pre_items_publish', { - 'intended_item_publish_count': intended_item_publish_count - }) - - if response: - frappe.db.set_value("Marketplace Settings", "Marketplace Settings", "sync_in_progress", 1) - return response - else: - frappe.throw(_('Unable to update remote activity')) - - -def item_sync_postprocess(): - response = call_hub_method('post_items_publish', {}) - if response: - frappe.db.set_value('Marketplace Settings', 'Marketplace Settings', 'last_sync_datetime', frappe.utils.now()) - else: - frappe.throw(_('Unable to update remote activity')) - - frappe.db.set_value('Marketplace Settings', 'Marketplace Settings', 'sync_in_progress', 0) - - -def convert_relative_image_urls_to_absolute(items): - from six.moves.urllib.parse import urljoin - - for item in items: - file_path = item['image'] - - if file_path.startswith('/files/'): - item['image'] = urljoin(frappe.utils.get_url(), file_path) - - -def get_hub_connection(): - settings = frappe.get_single('Marketplace Settings') - marketplace_url = settings.marketplace_url - hub_user = settings.get_hub_user(frappe.session.user) - - if hub_user: - password = hub_user.get_password() - hub_connection = FrappeClient(marketplace_url, hub_user.user, password) - return hub_connection - else: - read_only_hub_connection = FrappeClient(marketplace_url) - return read_only_hub_connection - - -def get_field_mappings(): - return [] diff --git a/erpnext/hub_node/data_migration_mapping/company_to_hub_company/company_to_hub_company.json b/erpnext/hub_node/data_migration_mapping/company_to_hub_company/company_to_hub_company.json deleted file mode 100644 index b1e421dada8..00000000000 --- a/erpnext/hub_node/data_migration_mapping/company_to_hub_company/company_to_hub_company.json +++ /dev/null @@ -1,50 +0,0 @@ -{ - "condition": "{'name': ('=', frappe.db.get_single_value('Hub Settings', 'company'))}", - "creation": "2017-09-07 11:38:43.169065", - "docstatus": 0, - "doctype": "Data Migration Mapping", - "fields": [ - { - "is_child_table": 0, - "local_fieldname": "name", - "remote_fieldname": "company_name" - }, - { - "is_child_table": 0, - "local_fieldname": "country", - "remote_fieldname": "country" - }, - { - "is_child_table": 0, - "local_fieldname": "\"city\"", - "remote_fieldname": "seller_city" - }, - { - "is_child_table": 0, - "local_fieldname": "eval:frappe.local.site", - "remote_fieldname": "site_name" - }, - { - "is_child_table": 0, - "local_fieldname": "eval:frappe.session.user", - "remote_fieldname": "user" - }, - { - "is_child_table": 0, - "local_fieldname": "company_logo", - "remote_fieldname": "company_logo" - } - ], - "idx": 2, - "local_doctype": "Company", - "mapping_name": "Company to Hub Company", - "mapping_type": "Push", - "migration_id_field": "hub_sync_id", - "modified": "2020-09-18 17:26:09.703215", - "modified_by": "Administrator", - "name": "Company to Hub Company", - "owner": "Administrator", - "page_length": 10, - "remote_objectname": "Hub Company", - "remote_primary_key": "name" -} \ No newline at end of file diff --git a/erpnext/hub_node/data_migration_mapping/hub_message_to_lead/hub_message_to_lead.json b/erpnext/hub_node/data_migration_mapping/hub_message_to_lead/hub_message_to_lead.json deleted file mode 100644 index d11abeb4b38..00000000000 --- a/erpnext/hub_node/data_migration_mapping/hub_message_to_lead/hub_message_to_lead.json +++ /dev/null @@ -1,31 +0,0 @@ -{ - "condition": "{'reference_doctype': 'Lead', 'user': frappe.db.get_single_value('Hub Settings', 'user'), 'status': 'Pending'}", - "creation": "2017-09-20 15:06:40.279930", - "docstatus": 0, - "doctype": "Data Migration Mapping", - "fields": [ - { - "is_child_table": 0, - "local_fieldname": "email_id", - "remote_fieldname": "email_id" - }, - { - "is_child_table": 0, - "local_fieldname": "lead_name", - "remote_fieldname": "lead_name" - } - ], - "idx": 0, - "local_doctype": "Lead", - "local_primary_key": "email_id", - "mapping_name": "Hub Message to Lead", - "mapping_type": "Pull", - "migration_id_field": "hub_sync_id", - "modified": "2020-09-18 17:26:09.703215", - "modified_by": "Administrator", - "name": "Hub Message to Lead", - "owner": "Administrator", - "page_length": 10, - "remote_objectname": "Hub Message", - "remote_primary_key": "name" -} \ No newline at end of file diff --git a/erpnext/hub_node/data_migration_mapping/item_to_hub_item/item_to_hub_item.json b/erpnext/hub_node/data_migration_mapping/item_to_hub_item/item_to_hub_item.json deleted file mode 100644 index bcece69b38c..00000000000 --- a/erpnext/hub_node/data_migration_mapping/item_to_hub_item/item_to_hub_item.json +++ /dev/null @@ -1,55 +0,0 @@ -{ - "condition": "{\"publish_in_hub\": 1}", - "creation": "2017-09-07 13:27:52.726350", - "docstatus": 0, - "doctype": "Data Migration Mapping", - "fields": [ - { - "is_child_table": 0, - "local_fieldname": "item_code", - "remote_fieldname": "item_code" - }, - { - "is_child_table": 0, - "local_fieldname": "item_name", - "remote_fieldname": "item_name" - }, - { - "is_child_table": 0, - "local_fieldname": "eval:frappe.db.get_value('Hub Settings' , 'Hub Settings', 'company_email')", - "remote_fieldname": "hub_seller" - }, - { - "is_child_table": 0, - "local_fieldname": "image", - "remote_fieldname": "image" - }, - { - "is_child_table": 0, - "local_fieldname": "image_list", - "remote_fieldname": "image_list" - }, - { - "is_child_table": 0, - "local_fieldname": "item_group", - "remote_fieldname": "item_group" - }, - { - "is_child_table": 0, - "local_fieldname": "hub_category", - "remote_fieldname": "hub_category" - } - ], - "idx": 1, - "local_doctype": "Item", - "mapping_name": "Item to Hub Item", - "mapping_type": "Push", - "migration_id_field": "hub_sync_id", - "modified": "2018-08-19 22:20:25.727581", - "modified_by": "Administrator", - "name": "Item to Hub Item", - "owner": "Administrator", - "page_length": 10, - "remote_objectname": "Hub Item", - "remote_primary_key": "item_code" -} \ No newline at end of file diff --git a/erpnext/hub_node/data_migration_plan/hub_sync/hub_sync.json b/erpnext/hub_node/data_migration_plan/hub_sync/hub_sync.json deleted file mode 100644 index e90b1dd1e8d..00000000000 --- a/erpnext/hub_node/data_migration_plan/hub_sync/hub_sync.json +++ /dev/null @@ -1,19 +0,0 @@ -{ - "creation": "2017-09-07 11:39:38.445902", - "docstatus": 0, - "doctype": "Data Migration Plan", - "idx": 1, - "mappings": [ - { - "enabled": 1, - "mapping": "Item to Hub Item" - } - ], - "modified": "2018-08-19 22:20:25.644602", - "modified_by": "Administrator", - "module": "Hub Node", - "name": "Hub Sync", - "owner": "Administrator", - "plan_name": "Hub Sync", - "postprocess_method": "erpnext.hub_node.api.item_sync_postprocess" -} \ No newline at end of file diff --git a/erpnext/hub_node/doctype/__init__.py b/erpnext/hub_node/doctype/__init__.py deleted file mode 100644 index e69de29bb2d..00000000000 diff --git a/erpnext/hub_node/doctype/hub_tracked_item/__init__.py b/erpnext/hub_node/doctype/hub_tracked_item/__init__.py deleted file mode 100644 index e69de29bb2d..00000000000 diff --git a/erpnext/hub_node/doctype/hub_tracked_item/hub_tracked_item.js b/erpnext/hub_node/doctype/hub_tracked_item/hub_tracked_item.js deleted file mode 100644 index 660532d13df..00000000000 --- a/erpnext/hub_node/doctype/hub_tracked_item/hub_tracked_item.js +++ /dev/null @@ -1,8 +0,0 @@ -// Copyright (c) 2018, Frappe Technologies Pvt. Ltd. and contributors -// For license information, please see license.txt - -frappe.ui.form.on('Hub Tracked Item', { - refresh: function(frm) { - - } -}); diff --git a/erpnext/hub_node/doctype/hub_tracked_item/hub_tracked_item.json b/erpnext/hub_node/doctype/hub_tracked_item/hub_tracked_item.json deleted file mode 100644 index 7d07ba40938..00000000000 --- a/erpnext/hub_node/doctype/hub_tracked_item/hub_tracked_item.json +++ /dev/null @@ -1,210 +0,0 @@ -{ - "allow_copy": 0, - "allow_guest_to_view": 0, - "allow_import": 0, - "allow_rename": 0, - "autoname": "field:item_code", - "beta": 0, - "creation": "2018-03-18 09:33:50.267762", - "custom": 0, - "docstatus": 0, - "doctype": "DocType", - "document_type": "", - "editable_grid": 1, - "engine": "InnoDB", - "fields": [ - { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "item_code", - "fieldtype": "Data", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "label": "Item Code", - "length": 0, - "no_copy": 0, - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 1 - }, - { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "hub_category", - "fieldtype": "Data", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "label": "Hub Category", - "length": 0, - "no_copy": 0, - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 - }, - { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "published", - "fieldtype": "Check", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "label": "Published", - "length": 0, - "no_copy": 0, - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 - }, - { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "image_list", - "fieldtype": "Long Text", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "label": "Image List", - "length": 0, - "no_copy": 0, - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 - } - ], - "has_web_view": 0, - "hide_heading": 0, - "hide_toolbar": 0, - "idx": 0, - "image_view": 0, - "in_create": 0, - "is_submittable": 0, - "issingle": 0, - "istable": 0, - "max_attachments": 0, - "modified": "2019-12-10 11:37:35.951019", - "modified_by": "Administrator", - "module": "Hub Node", - "name": "Hub Tracked Item", - "name_case": "", - "owner": "Administrator", - "permissions": [ - { - "amend": 0, - "cancel": 0, - "create": 1, - "delete": 1, - "email": 1, - "export": 1, - "if_owner": 0, - "import": 0, - "permlevel": 0, - "print": 1, - "read": 1, - "report": 1, - "role": "System Manager", - "set_user_permissions": 0, - "share": 1, - "submit": 0, - "write": 1 - }, - { - "amend": 0, - "cancel": 0, - "create": 1, - "delete": 1, - "email": 1, - "export": 1, - "if_owner": 0, - "import": 0, - "permlevel": 0, - "print": 1, - "read": 1, - "report": 1, - "role": "Item Manager", - "set_user_permissions": 0, - "share": 1, - "submit": 0, - "write": 1 - } - ], - "quick_entry": 1, - "read_only": 1, - "read_only_onload": 0, - "show_name_in_global_search": 0, - "sort_field": "modified", - "sort_order": "DESC", - "track_changes": 1, - "track_seen": 0, - "track_views": 0 -} \ No newline at end of file diff --git a/erpnext/hub_node/doctype/hub_tracked_item/hub_tracked_item.py b/erpnext/hub_node/doctype/hub_tracked_item/hub_tracked_item.py deleted file mode 100644 index 823c79eb72b..00000000000 --- a/erpnext/hub_node/doctype/hub_tracked_item/hub_tracked_item.py +++ /dev/null @@ -1,11 +0,0 @@ -# -*- coding: utf-8 -*- -# Copyright (c) 2018, Frappe Technologies Pvt. Ltd. and contributors -# For license information, please see license.txt - -from __future__ import unicode_literals - -from frappe.model.document import Document - - -class HubTrackedItem(Document): - pass diff --git a/erpnext/hub_node/doctype/hub_tracked_item/test_hub_tracked_item.py b/erpnext/hub_node/doctype/hub_tracked_item/test_hub_tracked_item.py deleted file mode 100644 index c403f902a2c..00000000000 --- a/erpnext/hub_node/doctype/hub_tracked_item/test_hub_tracked_item.py +++ /dev/null @@ -1,10 +0,0 @@ -# -*- coding: utf-8 -*- -# Copyright (c) 2018, Frappe Technologies Pvt. Ltd. and Contributors -# See license.txt -from __future__ import unicode_literals - -import unittest - - -class TestHubTrackedItem(unittest.TestCase): - pass diff --git a/erpnext/hub_node/doctype/hub_user/__init__.py b/erpnext/hub_node/doctype/hub_user/__init__.py deleted file mode 100644 index e69de29bb2d..00000000000 diff --git a/erpnext/hub_node/doctype/hub_user/hub_user.json b/erpnext/hub_node/doctype/hub_user/hub_user.json deleted file mode 100644 index f51ffb4387d..00000000000 --- a/erpnext/hub_node/doctype/hub_user/hub_user.json +++ /dev/null @@ -1,140 +0,0 @@ -{ - "allow_copy": 0, - "allow_guest_to_view": 0, - "allow_import": 0, - "allow_rename": 0, - "autoname": "", - "beta": 0, - "creation": "2018-08-31 12:36:45.627531", - "custom": 0, - "docstatus": 0, - "doctype": "DocType", - "document_type": "", - "editable_grid": 1, - "engine": "InnoDB", - "fields": [ - { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "user", - "fieldtype": "Link", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 1, - "in_standard_filter": 0, - "label": "User", - "length": 0, - "no_copy": 0, - "options": "User", - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 1, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 1 - }, - { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "hub_user_name", - "fieldtype": "Data", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 1, - "in_standard_filter": 0, - "label": "Hub User", - "length": 0, - "no_copy": 0, - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 1, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 - }, - { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "password", - "fieldtype": "Password", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 1, - "in_standard_filter": 0, - "label": "Hub Password", - "length": 0, - "no_copy": 0, - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 1, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 - } - ], - "has_web_view": 0, - "hide_heading": 0, - "hide_toolbar": 0, - "idx": 0, - "image_view": 0, - "in_create": 0, - "is_submittable": 0, - "issingle": 0, - "istable": 1, - "max_attachments": 0, - "modified": "2020-09-18 17:26:09.703215", - "modified_by": "Administrator", - "module": "Hub Node", - "name": "Hub User", - "name_case": "", - "owner": "Administrator", - "permissions": [], - "quick_entry": 1, - "read_only": 0, - "read_only_onload": 0, - "show_name_in_global_search": 0, - "sort_field": "modified", - "sort_order": "DESC", - "track_changes": 1, - "track_seen": 0, - "track_views": 0 -} \ No newline at end of file diff --git a/erpnext/hub_node/doctype/hub_user/hub_user.py b/erpnext/hub_node/doctype/hub_user/hub_user.py deleted file mode 100644 index 1f7c8fc3f20..00000000000 --- a/erpnext/hub_node/doctype/hub_user/hub_user.py +++ /dev/null @@ -1,11 +0,0 @@ -# -*- coding: utf-8 -*- -# Copyright (c) 2018, Frappe Technologies Pvt. Ltd. and contributors -# For license information, please see license.txt - -from __future__ import unicode_literals - -from frappe.model.document import Document - - -class HubUser(Document): - pass diff --git a/erpnext/hub_node/doctype/hub_users/__init__.py b/erpnext/hub_node/doctype/hub_users/__init__.py deleted file mode 100644 index e69de29bb2d..00000000000 diff --git a/erpnext/hub_node/doctype/hub_users/hub_users.json b/erpnext/hub_node/doctype/hub_users/hub_users.json deleted file mode 100644 index d42f3fdf1b7..00000000000 --- a/erpnext/hub_node/doctype/hub_users/hub_users.json +++ /dev/null @@ -1,72 +0,0 @@ -{ - "allow_copy": 0, - "allow_guest_to_view": 0, - "allow_import": 0, - "allow_rename": 0, - "beta": 0, - "creation": "2018-03-06 04:38:49.891787", - "custom": 0, - "docstatus": 0, - "doctype": "DocType", - "document_type": "", - "editable_grid": 1, - "engine": "InnoDB", - "fields": [ - { - "allow_bulk_edit": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "user", - "fieldtype": "Link", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 1, - "in_standard_filter": 0, - "label": "User", - "length": 0, - "no_copy": 0, - "options": "User", - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 1, - "search_index": 0, - "set_only_once": 0, - "unique": 0 - } - ], - "has_web_view": 0, - "hide_heading": 0, - "hide_toolbar": 0, - "idx": 0, - "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": "Hub Node", - "name": "Hub Users", - "name_case": "", - "owner": "Administrator", - "permissions": [], - "quick_entry": 1, - "read_only": 0, - "read_only_onload": 0, - "show_name_in_global_search": 0, - "sort_field": "modified", - "sort_order": "DESC", - "track_changes": 1, - "track_seen": 0 -} \ No newline at end of file diff --git a/erpnext/hub_node/doctype/hub_users/hub_users.py b/erpnext/hub_node/doctype/hub_users/hub_users.py deleted file mode 100644 index e08ed68ed8f..00000000000 --- a/erpnext/hub_node/doctype/hub_users/hub_users.py +++ /dev/null @@ -1,11 +0,0 @@ -# -*- coding: utf-8 -*- -# Copyright (c) 2018, Frappe Technologies Pvt. Ltd. and contributors -# For license information, please see license.txt - -from __future__ import unicode_literals - -from frappe.model.document import Document - - -class HubUsers(Document): - pass diff --git a/erpnext/hub_node/doctype/marketplace_settings/__init__.py b/erpnext/hub_node/doctype/marketplace_settings/__init__.py deleted file mode 100644 index e69de29bb2d..00000000000 diff --git a/erpnext/hub_node/doctype/marketplace_settings/marketplace_settings.js b/erpnext/hub_node/doctype/marketplace_settings/marketplace_settings.js deleted file mode 100644 index 36da832c7c0..00000000000 --- a/erpnext/hub_node/doctype/marketplace_settings/marketplace_settings.js +++ /dev/null @@ -1,8 +0,0 @@ -// Copyright (c) 2018, Frappe Technologies Pvt. Ltd. and contributors -// For license information, please see license.txt - -frappe.ui.form.on('Marketplace Settings', { - refresh: function(frm) { - $('#toolbar-user .marketplace-link').toggle(!frm.doc.disable_marketplace); - }, -}); diff --git a/erpnext/hub_node/doctype/marketplace_settings/marketplace_settings.json b/erpnext/hub_node/doctype/marketplace_settings/marketplace_settings.json deleted file mode 100644 index e784f68fcf3..00000000000 --- a/erpnext/hub_node/doctype/marketplace_settings/marketplace_settings.json +++ /dev/null @@ -1,410 +0,0 @@ -{ - "allow_copy": 0, - "allow_events_in_timeline": 0, - "allow_guest_to_view": 0, - "allow_import": 0, - "allow_rename": 0, - "beta": 1, - "creation": "2018-08-31 15:54:38.795263", - "custom": 0, - "description": "", - "docstatus": 0, - "doctype": "DocType", - "document_type": "", - "editable_grid": 0, - "engine": "InnoDB", - "fields": [ - { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "disable_marketplace", - "fieldtype": "Check", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "label": "Disable Marketplace", - "length": 0, - "no_copy": 0, - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 - }, - { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "depends_on": "eval:!doc.disable_marketplace", - "fieldname": "marketplace_settings_section", - "fieldtype": "Section Break", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "label": "Marketplace Settings", - "length": 0, - "no_copy": 0, - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 - }, - { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "default": "https://hubmarket.org", - "fieldname": "marketplace_url", - "fieldtype": "Data", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "label": "Marketplace URL (to hide and update label)", - "length": 0, - "no_copy": 0, - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 - }, - { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "registered", - "fieldtype": "Check", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "label": "Registered", - "length": 0, - "no_copy": 0, - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 - }, - { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "sync_in_progress", - "fieldtype": "Check", - "hidden": 1, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "label": "Sync in Progress", - "length": 0, - "no_copy": 0, - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 - }, - { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "company", - "fieldtype": "Link", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 1, - "in_standard_filter": 0, - "label": "Company", - "length": 0, - "no_copy": 0, - "options": "Company", - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 - }, - { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "hub_seller_name", - "fieldtype": "Data", - "hidden": 1, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "label": "Hub Seller Name", - "length": 0, - "no_copy": 0, - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 - }, - { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "users", - "fieldtype": "Table", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "label": "Users", - "length": 0, - "no_copy": 0, - "options": "Hub User", - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 - }, - { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "depends_on": "", - "fieldname": "last_sync_datetime", - "fieldtype": "Datetime", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "label": "Last Sync On", - "length": 0, - "no_copy": 0, - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 - }, - { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "default": "", - "depends_on": "eval:1", - "fieldname": "custom_data", - "fieldtype": "Code", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "label": "Custom Data", - "length": 0, - "no_copy": 0, - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 1, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 - } - ], - "has_web_view": 0, - "hide_heading": 0, - "hide_toolbar": 0, - "idx": 0, - "image_view": 0, - "in_create": 0, - "is_submittable": 0, - "issingle": 1, - "istable": 0, - "max_attachments": 0, - "modified": "2020-09-18 17:26:09.703215", - "modified_by": "Administrator", - "module": "Hub Node", - "name": "Marketplace Settings", - "name_case": "", - "owner": "Administrator", - "permissions": [ - { - "amend": 0, - "cancel": 0, - "create": 1, - "delete": 0, - "email": 0, - "export": 0, - "if_owner": 0, - "import": 0, - "permlevel": 0, - "print": 0, - "read": 1, - "report": 0, - "role": "System Manager", - "set_user_permissions": 0, - "share": 0, - "submit": 0, - "write": 1 - }, - { - "amend": 0, - "cancel": 0, - "create": 0, - "delete": 0, - "email": 1, - "export": 0, - "if_owner": 0, - "import": 0, - "permlevel": 0, - "print": 1, - "read": 1, - "report": 0, - "role": "All", - "set_user_permissions": 0, - "share": 1, - "submit": 0, - "write": 0 - } - ], - "quick_entry": 0, - "read_only": 0, - "read_only_onload": 0, - "show_name_in_global_search": 0, - "sort_field": "modified", - "sort_order": "DESC", - "track_changes": 1, - "track_seen": 0, - "track_views": 0 -} \ No newline at end of file diff --git a/erpnext/hub_node/doctype/marketplace_settings/marketplace_settings.py b/erpnext/hub_node/doctype/marketplace_settings/marketplace_settings.py deleted file mode 100644 index 33d23f6eae4..00000000000 --- a/erpnext/hub_node/doctype/marketplace_settings/marketplace_settings.py +++ /dev/null @@ -1,93 +0,0 @@ -# Copyright (c) 2018, Frappe Technologies Pvt. Ltd. and Contributors and contributors -# For license information, please see license.txt - -from __future__ import unicode_literals - -import json - -import frappe -from frappe.frappeclient import FrappeClient -from frappe.model.document import Document -from frappe.utils import cint - - -class MarketplaceSettings(Document): - - def register_seller(self, company, company_description): - - country, currency, company_logo = frappe.db.get_value('Company', company, - ['country', 'default_currency', 'company_logo']) - - company_details = { - 'company': company, - 'country': country, - 'currency': currency, - 'company_description': company_description, - 'company_logo': company_logo, - 'site_name': frappe.utils.get_url() - } - - hub_connection = self.get_connection() - - response = hub_connection.post_request({ - 'cmd': 'hub.hub.api.add_hub_seller', - 'company_details': json.dumps(company_details) - }) - - return response - - - def add_hub_user(self, user_email): - '''Create a Hub User and User record on hub server - and if successfull append it to Hub User table - ''' - - if not self.registered: - return - - hub_connection = self.get_connection() - - first_name, last_name = frappe.db.get_value('User', user_email, ['first_name', 'last_name']) - - hub_user = hub_connection.post_request({ - 'cmd': 'hub.hub.api.add_hub_user', - 'user_email': user_email, - 'first_name': first_name, - 'last_name': last_name, - 'hub_seller': self.hub_seller_name - }) - - self.append('users', { - 'user': hub_user.get('user_email'), - 'hub_user_name': hub_user.get('hub_user_name'), - 'password': hub_user.get('password') - }) - - self.save() - - def get_hub_user(self, user): - '''Return the Hub User doc from the `users` table if password is set''' - - filtered_users = list(filter( - lambda x: x.user == user and x.password, - self.users - )) - - if filtered_users: - return filtered_users[0] - - - def get_connection(self): - return FrappeClient(self.marketplace_url) - - - def unregister(self): - """Disable the User on hubmarket.org""" - -@frappe.whitelist() -def is_marketplace_enabled(): - if not hasattr(frappe.local, 'is_marketplace_enabled'): - frappe.local.is_marketplace_enabled = cint(frappe.db.get_single_value('Marketplace Settings', - 'disable_marketplace')) - - return frappe.local.is_marketplace_enabled diff --git a/erpnext/hub_node/doctype/marketplace_settings/test_marketplace_settings.py b/erpnext/hub_node/doctype/marketplace_settings/test_marketplace_settings.py deleted file mode 100644 index 7922f45ab59..00000000000 --- a/erpnext/hub_node/doctype/marketplace_settings/test_marketplace_settings.py +++ /dev/null @@ -1,10 +0,0 @@ -# -*- coding: utf-8 -*- -# Copyright (c) 2018, Frappe Technologies Pvt. Ltd. and Contributors -# See license.txt -from __future__ import unicode_literals - -import unittest - - -class TestMarketplaceSettings(unittest.TestCase): - pass diff --git a/erpnext/hub_node/legacy.py b/erpnext/hub_node/legacy.py deleted file mode 100644 index 2e4c2668436..00000000000 --- a/erpnext/hub_node/legacy.py +++ /dev/null @@ -1,148 +0,0 @@ -from __future__ import unicode_literals - -import json - -import frappe -from frappe.contacts.doctype.contact.contact import get_default_contact -from frappe.frappeclient import FrappeClient -from frappe.utils import nowdate -from frappe.utils.nestedset import get_root_of - - -def get_list(doctype, start, limit, fields, filters, order_by): - pass - -def get_hub_connection(): - if frappe.db.exists('Data Migration Connector', 'Hub Connector'): - hub_connector = frappe.get_doc('Data Migration Connector', 'Hub Connector') - hub_connection = hub_connector.get_connection() - return hub_connection.connection - - # read-only connection - hub_connection = FrappeClient(frappe.conf.hub_url) - return hub_connection - -def make_opportunity(buyer_name, email_id): - buyer_name = "HUB-" + buyer_name - - if not frappe.db.exists('Lead', {'email_id': email_id}): - lead = frappe.new_doc("Lead") - lead.lead_name = buyer_name - lead.email_id = email_id - lead.save(ignore_permissions=True) - - o = frappe.new_doc("Opportunity") - o.opportunity_from = "Lead" - o.lead = frappe.get_all("Lead", filters={"email_id": email_id}, fields = ["name"])[0]["name"] - o.save(ignore_permissions=True) - -@frappe.whitelist() -def make_rfq_and_send_opportunity(item, supplier): - supplier = make_supplier(supplier) - contact = make_contact(supplier) - item = make_item(item) - rfq = make_rfq(item, supplier, contact) - status = send_opportunity(contact) - - return { - 'rfq': rfq, - 'hub_document_created': status - } - -def make_supplier(supplier): - # make supplier if not already exists - supplier = frappe._dict(json.loads(supplier)) - - if not frappe.db.exists('Supplier', {'supplier_name': supplier.supplier_name}): - supplier_doc = frappe.get_doc({ - 'doctype': 'Supplier', - 'supplier_name': supplier.supplier_name, - 'supplier_group': supplier.supplier_group, - 'supplier_email': supplier.supplier_email - }).insert() - else: - supplier_doc = frappe.get_doc('Supplier', supplier.supplier_name) - - return supplier_doc - -def make_contact(supplier): - contact_name = get_default_contact('Supplier', supplier.supplier_name) - # make contact if not already exists - if not contact_name: - contact = frappe.get_doc({ - 'doctype': 'Contact', - 'first_name': supplier.supplier_name, - 'is_primary_contact': 1, - 'links': [ - {'link_doctype': 'Supplier', 'link_name': supplier.supplier_name} - ] - }) - contact.add_email(supplier.supplier_email, is_primary=True) - contact.insert() - else: - contact = frappe.get_doc('Contact', contact_name) - - return contact - -def make_item(item): - # make item if not already exists - item = frappe._dict(json.loads(item)) - - if not frappe.db.exists('Item', {'item_code': item.item_code}): - item_doc = frappe.get_doc({ - 'doctype': 'Item', - 'item_code': item.item_code, - 'item_group': item.item_group, - 'is_item_from_hub': 1 - }).insert() - else: - item_doc = frappe.get_doc('Item', item.item_code) - - return item_doc - -def make_rfq(item, supplier, contact): - # make rfq - rfq = frappe.get_doc({ - 'doctype': 'Request for Quotation', - 'transaction_date': nowdate(), - 'status': 'Draft', - 'company': frappe.db.get_single_value('Marketplace Settings', 'company'), - 'message_for_supplier': 'Please supply the specified items at the best possible rates', - 'suppliers': [ - { 'supplier': supplier.name, 'contact': contact.name } - ], - 'items': [ - { - 'item_code': item.item_code, - 'qty': 1, - 'schedule_date': nowdate(), - 'warehouse': item.default_warehouse or get_root_of("Warehouse"), - 'description': item.description, - 'uom': item.stock_uom - } - ] - }).insert() - - rfq.save() - rfq.submit() - return rfq - -def send_opportunity(contact): - # Make Hub Message on Hub with lead data - doc = { - 'doctype': 'Lead', - 'lead_name': frappe.db.get_single_value('Marketplace Settings', 'company'), - 'email_id': frappe.db.get_single_value('Marketplace Settings', 'user') - } - - args = frappe._dict(dict( - doctype='Hub Message', - reference_doctype='Lead', - data=json.dumps(doc), - user=contact.email_id - )) - - connection = get_hub_connection() - response = connection.insert('Hub Message', args) - - return response.ok diff --git a/erpnext/loan_management/dashboard_chart_source/top_10_pledged_loan_securities/top_10_pledged_loan_securities.py b/erpnext/loan_management/dashboard_chart_source/top_10_pledged_loan_securities/top_10_pledged_loan_securities.py index 0911e8f49bb..6144d9d39a4 100644 --- a/erpnext/loan_management/dashboard_chart_source/top_10_pledged_loan_securities/top_10_pledged_loan_securities.py +++ b/erpnext/loan_management/dashboard_chart_source/top_10_pledged_loan_securities/top_10_pledged_loan_securities.py @@ -1,11 +1,9 @@ # Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors # License: GNU General Public License v3. See license.txt -from __future__ import unicode_literals import frappe from frappe.utils.dashboard import cache_source -from six import iteritems from erpnext.loan_management.report.applicant_wise_loan_security_exposure.applicant_wise_loan_security_exposure import ( get_loan_security_details, @@ -54,14 +52,14 @@ def get_data(chart_name = None, chart = None, no_cache = None, filters = None, f GROUP BY p.loan_security """.format(conditions=conditions), filters, as_list=1)) - for security, qty in iteritems(pledges): + for security, qty in pledges.items(): current_pledges.setdefault(security, qty) current_pledges[security] -= unpledges.get(security, 0.0) sorted_pledges = dict(sorted(current_pledges.items(), key=lambda item: item[1], reverse=True)) count = 0 - for security, qty in iteritems(sorted_pledges): + for security, qty in sorted_pledges.items(): values.append(qty * loan_security_details.get(security, {}).get('latest_price', 0)) labels.append(security) count +=1 diff --git a/erpnext/loan_management/doctype/loan/loan.json b/erpnext/loan_management/doctype/loan/loan.json index c9f23ca4df3..5979992bbe8 100644 --- a/erpnext/loan_management/doctype/loan/loan.json +++ b/erpnext/loan_management/doctype/loan/loan.json @@ -334,7 +334,6 @@ }, { "depends_on": "eval:doc.is_secured_loan", - "fetch_from": "loan_application.maximum_loan_amount", "fieldname": "maximum_loan_amount", "fieldtype": "Currency", "label": "Maximum Loan Amount", @@ -360,7 +359,7 @@ "index_web_pages_for_search": 1, "is_submittable": 1, "links": [], - "modified": "2021-04-19 18:10:32.360818", + "modified": "2021-10-12 18:10:32.360818", "modified_by": "Administrator", "module": "Loan Management", "name": "Loan", diff --git a/erpnext/loan_management/doctype/loan/loan.py b/erpnext/loan_management/doctype/loan/loan.py index 7dbd42297e1..84e0f03bae9 100644 --- a/erpnext/loan_management/doctype/loan/loan.py +++ b/erpnext/loan_management/doctype/loan/loan.py @@ -1,8 +1,6 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2019, Frappe Technologies Pvt. Ltd. and contributors # For license information, please see license.txt -from __future__ import unicode_literals import json import math @@ -10,7 +8,6 @@ import math import frappe from frappe import _ from frappe.utils import add_months, flt, getdate, now_datetime, nowdate -from six import string_types import erpnext from erpnext.controllers.accounts_controller import AccountsController @@ -137,16 +134,23 @@ class Loan(AccountsController): frappe.throw(_("Loan amount is mandatory")) def link_loan_security_pledge(self): - if self.is_secured_loan: - loan_security_pledge = frappe.db.get_value('Loan Security Pledge', {'loan_application': self.loan_application}, - 'name') + if self.is_secured_loan and self.loan_application: + maximum_loan_value = frappe.db.get_value('Loan Security Pledge', + { + 'loan_application': self.loan_application, + 'status': 'Requested' + }, + 'sum(maximum_loan_value)' + ) - if loan_security_pledge: - frappe.db.set_value('Loan Security Pledge', loan_security_pledge, { - 'loan': self.name, - 'status': 'Pledged', - 'pledge_time': now_datetime() - }) + if maximum_loan_value: + frappe.db.sql(""" + UPDATE `tabLoan Security Pledge` + SET loan = %s, pledge_time = %s, status = 'Pledged' + WHERE status = 'Requested' and loan_application = %s + """, (self.name, now_datetime(), self.loan_application)) + + self.db_set('maximum_loan_amount', maximum_loan_value) def unlink_loan_security_pledge(self): pledges = frappe.get_all('Loan Security Pledge', fields=['name'], filters={'loan': self.name}) @@ -316,7 +320,7 @@ def make_loan_write_off(loan, company=None, posting_date=None, amount=0, as_dict @frappe.whitelist() def unpledge_security(loan=None, loan_security_pledge=None, security_map=None, as_dict=0, save=0, submit=0, approve=0): # if no security_map is passed it will be considered as full unpledge - if security_map and isinstance(security_map, string_types): + if security_map and isinstance(security_map, str): security_map = json.loads(security_map) if loan: diff --git a/erpnext/loan_management/doctype/loan/loan_dashboard.py b/erpnext/loan_management/doctype/loan/loan_dashboard.py index 28ccc03b684..c8a9e64f5ef 100644 --- a/erpnext/loan_management/doctype/loan/loan_dashboard.py +++ b/erpnext/loan_management/doctype/loan/loan_dashboard.py @@ -1,6 +1,3 @@ -from __future__ import unicode_literals - - def get_data(): return { 'fieldname': 'loan', diff --git a/erpnext/loan_management/doctype/loan/test_loan.py b/erpnext/loan_management/doctype/loan/test_loan.py index ec0aebbb8a4..c0f058feae6 100644 --- a/erpnext/loan_management/doctype/loan/test_loan.py +++ b/erpnext/loan_management/doctype/loan/test_loan.py @@ -1,7 +1,5 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2019, Frappe Technologies Pvt. Ltd. and Contributors # See license.txt -from __future__ import unicode_literals import unittest diff --git a/erpnext/loan_management/doctype/loan_application/loan_application.py b/erpnext/loan_management/doctype/loan_application/loan_application.py index e492920abb3..24d8d68de0b 100644 --- a/erpnext/loan_management/doctype/loan_application/loan_application.py +++ b/erpnext/loan_management/doctype/loan_application/loan_application.py @@ -1,8 +1,6 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2019, Frappe Technologies Pvt. Ltd. and contributors # For license information, please see license.txt -from __future__ import unicode_literals import json import math @@ -12,7 +10,6 @@ from frappe import _ from frappe.model.document import Document from frappe.model.mapper import get_mapped_doc from frappe.utils import cint, flt, rounded -from six import string_types from erpnext.loan_management.doctype.loan.loan import ( get_monthly_repayment_amount, @@ -130,10 +127,11 @@ class LoanApplication(Document): def create_loan(source_name, target_doc=None, submit=0): def update_accounts(source_doc, target_doc, source_parent): account_details = frappe.get_all("Loan Type", - fields=["mode_of_payment", "payment_account","loan_account", "interest_income_account", "penalty_income_account"], - filters = {'name': source_doc.loan_type} - )[0] + fields=["mode_of_payment", "payment_account","loan_account", "interest_income_account", "penalty_income_account"], + filters = {'name': source_doc.loan_type})[0] + if source_doc.is_secured_loan: + target_doc.maximum_loan_amount = 0 target_doc.mode_of_payment = account_details.mode_of_payment target_doc.payment_account = account_details.payment_account @@ -191,7 +189,7 @@ def create_pledge(loan_application, loan=None): #This is a sandbox method to get the proposed pledges @frappe.whitelist() def get_proposed_pledge(securities): - if isinstance(securities, string_types): + if isinstance(securities, str): securities = json.loads(securities) proposed_pledges = { diff --git a/erpnext/loan_management/doctype/loan_application/loan_application_dashboard.py b/erpnext/loan_management/doctype/loan_application/loan_application_dashboard.py index 992d6699747..e8e2a2a0de6 100644 --- a/erpnext/loan_management/doctype/loan_application/loan_application_dashboard.py +++ b/erpnext/loan_management/doctype/loan_application/loan_application_dashboard.py @@ -1,6 +1,3 @@ -from __future__ import unicode_literals - - def get_data(): return { 'fieldname': 'loan_application', diff --git a/erpnext/loan_management/doctype/loan_application/test_loan_application.py b/erpnext/loan_management/doctype/loan_application/test_loan_application.py index aefa08970a4..d367e92ac49 100644 --- a/erpnext/loan_management/doctype/loan_application/test_loan_application.py +++ b/erpnext/loan_management/doctype/loan_application/test_loan_application.py @@ -1,7 +1,5 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2019, Frappe Technologies Pvt. Ltd. and Contributors # See license.txt -from __future__ import unicode_literals import unittest diff --git a/erpnext/loan_management/doctype/loan_disbursement/loan_disbursement.py b/erpnext/loan_management/doctype/loan_disbursement/loan_disbursement.py index 6d9d4f490d3..93b4af92c76 100644 --- a/erpnext/loan_management/doctype/loan_disbursement/loan_disbursement.py +++ b/erpnext/loan_management/doctype/loan_disbursement/loan_disbursement.py @@ -1,8 +1,6 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2019, Frappe Technologies Pvt. Ltd. and contributors # For license information, please see license.txt -from __future__ import unicode_literals import frappe from frappe import _ @@ -198,7 +196,7 @@ def get_disbursal_amount(loan, on_current_security_price=0): security_value = get_total_pledged_security_value(loan) if loan_details.is_secured_loan and not on_current_security_price: - security_value = flt(loan_details.maximum_loan_amount) + security_value = get_maximum_amount_as_per_pledged_security(loan) if not security_value and not loan_details.is_secured_loan: security_value = flt(loan_details.loan_amount) @@ -209,3 +207,6 @@ def get_disbursal_amount(loan, on_current_security_price=0): disbursal_amount = loan_details.loan_amount - loan_details.disbursed_amount return disbursal_amount + +def get_maximum_amount_as_per_pledged_security(loan): + return flt(frappe.db.get_value('Loan Security Pledge', {'loan': loan}, 'sum(maximum_loan_value)')) diff --git a/erpnext/loan_management/doctype/loan_disbursement/test_loan_disbursement.py b/erpnext/loan_management/doctype/loan_disbursement/test_loan_disbursement.py index b17c9a177e0..94ec84ea5db 100644 --- a/erpnext/loan_management/doctype/loan_disbursement/test_loan_disbursement.py +++ b/erpnext/loan_management/doctype/loan_disbursement/test_loan_disbursement.py @@ -1,7 +1,5 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2019, Frappe Technologies Pvt. Ltd. and Contributors # See license.txt -from __future__ import unicode_literals import unittest diff --git a/erpnext/loan_management/doctype/loan_interest_accrual/loan_interest_accrual.py b/erpnext/loan_management/doctype/loan_interest_accrual/loan_interest_accrual.py index 93513a83e7e..e945d4931e3 100644 --- a/erpnext/loan_management/doctype/loan_interest_accrual/loan_interest_accrual.py +++ b/erpnext/loan_management/doctype/loan_interest_accrual/loan_interest_accrual.py @@ -1,8 +1,6 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2019, Frappe Technologies Pvt. Ltd. and contributors # For license information, please see license.txt -from __future__ import unicode_literals import frappe from frappe import _ diff --git a/erpnext/loan_management/doctype/loan_interest_accrual/test_loan_interest_accrual.py b/erpnext/loan_management/doctype/loan_interest_accrual/test_loan_interest_accrual.py index 06b801e47c5..46aaaad9fd2 100644 --- a/erpnext/loan_management/doctype/loan_interest_accrual/test_loan_interest_accrual.py +++ b/erpnext/loan_management/doctype/loan_interest_accrual/test_loan_interest_accrual.py @@ -1,7 +1,5 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2019, Frappe Technologies Pvt. Ltd. and Contributors # See license.txt -from __future__ import unicode_literals import unittest diff --git a/erpnext/loan_management/doctype/loan_repayment/loan_repayment.py b/erpnext/loan_management/doctype/loan_repayment/loan_repayment.py index 13b73573274..5922e4f902a 100644 --- a/erpnext/loan_management/doctype/loan_repayment/loan_repayment.py +++ b/erpnext/loan_management/doctype/loan_repayment/loan_repayment.py @@ -1,13 +1,10 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2019, Frappe Technologies Pvt. Ltd. and contributors # For license information, please see license.txt -from __future__ import unicode_literals import frappe from frappe import _ from frappe.utils import add_days, cint, date_diff, flt, get_datetime, getdate -from six import iteritems import erpnext from erpnext.accounts.general_ledger import make_gl_entries @@ -189,7 +186,7 @@ class LoanRepayment(AccountsController): # interest_paid = self.amount_paid - self.principal_amount_paid - self.penalty_amount if interest_paid > 0: - for lia, amounts in iteritems(repayment_details.get('pending_accrual_entries', [])): + for lia, amounts in repayment_details.get('pending_accrual_entries', []).items(): if amounts['interest_amount'] + amounts['payable_principal_amount'] <= interest_paid: interest_amount = amounts['interest_amount'] paid_principal = amounts['payable_principal_amount'] @@ -411,7 +408,7 @@ def get_amounts(amounts, against_loan, posting_date): if due_date and not final_due_date: final_due_date = add_days(due_date, loan_type_details.grace_period_in_days) - if against_loan_doc.status in ('Disbursed', 'Loan Closure Requested', 'Closed'): + if against_loan_doc.status in ('Disbursed', 'Closed') or against_loan_doc.disbursed_amount >= against_loan_doc.loan_amount: pending_principal_amount = against_loan_doc.total_payment - against_loan_doc.total_principal_paid \ - against_loan_doc.total_interest_payable - against_loan_doc.written_off_amount else: diff --git a/erpnext/loan_management/doctype/loan_repayment/test_loan_repayment.py b/erpnext/loan_management/doctype/loan_repayment/test_loan_repayment.py index c6ca630e599..98e5a0a6af3 100644 --- a/erpnext/loan_management/doctype/loan_repayment/test_loan_repayment.py +++ b/erpnext/loan_management/doctype/loan_repayment/test_loan_repayment.py @@ -1,7 +1,5 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2019, Frappe Technologies Pvt. Ltd. and Contributors # See license.txt -from __future__ import unicode_literals # import frappe import unittest diff --git a/erpnext/loan_management/doctype/loan_repayment_detail/loan_repayment_detail.py b/erpnext/loan_management/doctype/loan_repayment_detail/loan_repayment_detail.py index 495466c382e..495b6866615 100644 --- a/erpnext/loan_management/doctype/loan_repayment_detail/loan_repayment_detail.py +++ b/erpnext/loan_management/doctype/loan_repayment_detail/loan_repayment_detail.py @@ -1,8 +1,6 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2020, Frappe Technologies Pvt. Ltd. and contributors # For license information, please see license.txt -from __future__ import unicode_literals # import frappe from frappe.model.document import Document diff --git a/erpnext/loan_management/doctype/loan_security/loan_security.py b/erpnext/loan_management/doctype/loan_security/loan_security.py index 91cce67852a..8087fc50959 100644 --- a/erpnext/loan_management/doctype/loan_security/loan_security.py +++ b/erpnext/loan_management/doctype/loan_security/loan_security.py @@ -1,8 +1,6 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2019, Frappe Technologies Pvt. Ltd. and contributors # For license information, please see license.txt -from __future__ import unicode_literals # import frappe from frappe.model.document import Document diff --git a/erpnext/loan_management/doctype/loan_security/loan_security_dashboard.py b/erpnext/loan_management/doctype/loan_security/loan_security_dashboard.py index 35f3ba6830f..964a1ae93a7 100644 --- a/erpnext/loan_management/doctype/loan_security/loan_security_dashboard.py +++ b/erpnext/loan_management/doctype/loan_security/loan_security_dashboard.py @@ -1,6 +1,3 @@ -from __future__ import unicode_literals - - def get_data(): return { 'fieldname': 'loan_security', diff --git a/erpnext/loan_management/doctype/loan_security/test_loan_security.py b/erpnext/loan_management/doctype/loan_security/test_loan_security.py index 910b658a93c..7e702ed2345 100644 --- a/erpnext/loan_management/doctype/loan_security/test_loan_security.py +++ b/erpnext/loan_management/doctype/loan_security/test_loan_security.py @@ -1,7 +1,5 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2019, Frappe Technologies Pvt. Ltd. and Contributors # See license.txt -from __future__ import unicode_literals # import frappe import unittest diff --git a/erpnext/loan_management/doctype/loan_security_pledge/loan_security_pledge.py b/erpnext/loan_management/doctype/loan_security_pledge/loan_security_pledge.py index eb6c79ec4fc..7d02645609b 100644 --- a/erpnext/loan_management/doctype/loan_security_pledge/loan_security_pledge.py +++ b/erpnext/loan_management/doctype/loan_security_pledge/loan_security_pledge.py @@ -1,8 +1,6 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2019, Frappe Technologies Pvt. Ltd. and contributors # For license information, please see license.txt -from __future__ import unicode_literals import frappe from frappe import _ diff --git a/erpnext/loan_management/doctype/loan_security_pledge/test_loan_security_pledge.py b/erpnext/loan_management/doctype/loan_security_pledge/test_loan_security_pledge.py index 41bc78ede48..b9d05c28586 100644 --- a/erpnext/loan_management/doctype/loan_security_pledge/test_loan_security_pledge.py +++ b/erpnext/loan_management/doctype/loan_security_pledge/test_loan_security_pledge.py @@ -1,7 +1,5 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2019, Frappe Technologies Pvt. Ltd. and Contributors # See license.txt -from __future__ import unicode_literals # import frappe import unittest diff --git a/erpnext/loan_management/doctype/loan_security_price/loan_security_price.py b/erpnext/loan_management/doctype/loan_security_price/loan_security_price.py index 6ede6a2739f..fca9dd6bcb9 100644 --- a/erpnext/loan_management/doctype/loan_security_price/loan_security_price.py +++ b/erpnext/loan_management/doctype/loan_security_price/loan_security_price.py @@ -1,8 +1,6 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2019, Frappe Technologies Pvt. Ltd. and contributors # For license information, please see license.txt -from __future__ import unicode_literals import frappe from frappe import _ diff --git a/erpnext/loan_management/doctype/loan_security_price/test_loan_security_price.py b/erpnext/loan_management/doctype/loan_security_price/test_loan_security_price.py index ac630868427..aa533d9cf40 100644 --- a/erpnext/loan_management/doctype/loan_security_price/test_loan_security_price.py +++ b/erpnext/loan_management/doctype/loan_security_price/test_loan_security_price.py @@ -1,7 +1,5 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2019, Frappe Technologies Pvt. Ltd. and Contributors # See license.txt -from __future__ import unicode_literals # import frappe import unittest diff --git a/erpnext/loan_management/doctype/loan_security_shortfall/loan_security_shortfall.py b/erpnext/loan_management/doctype/loan_security_shortfall/loan_security_shortfall.py index 5863c03f0f4..20e451b81ea 100644 --- a/erpnext/loan_management/doctype/loan_security_shortfall/loan_security_shortfall.py +++ b/erpnext/loan_management/doctype/loan_security_shortfall/loan_security_shortfall.py @@ -1,8 +1,6 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2019, Frappe Technologies Pvt. Ltd. and contributors # For license information, please see license.txt -from __future__ import unicode_literals import frappe from frappe.model.document import Document diff --git a/erpnext/loan_management/doctype/loan_security_shortfall/test_loan_security_shortfall.py b/erpnext/loan_management/doctype/loan_security_shortfall/test_loan_security_shortfall.py index fefec43bf41..58bf9744380 100644 --- a/erpnext/loan_management/doctype/loan_security_shortfall/test_loan_security_shortfall.py +++ b/erpnext/loan_management/doctype/loan_security_shortfall/test_loan_security_shortfall.py @@ -1,7 +1,5 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2019, Frappe Technologies Pvt. Ltd. and Contributors # See license.txt -from __future__ import unicode_literals # import frappe import unittest diff --git a/erpnext/loan_management/doctype/loan_security_type/loan_security_type.py b/erpnext/loan_management/doctype/loan_security_type/loan_security_type.py index ca1957fb3aa..af87259daf5 100644 --- a/erpnext/loan_management/doctype/loan_security_type/loan_security_type.py +++ b/erpnext/loan_management/doctype/loan_security_type/loan_security_type.py @@ -1,8 +1,6 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2019, Frappe Technologies Pvt. Ltd. and contributors # For license information, please see license.txt -from __future__ import unicode_literals # import frappe from frappe.model.document import Document diff --git a/erpnext/loan_management/doctype/loan_security_type/loan_security_type_dashboard.py b/erpnext/loan_management/doctype/loan_security_type/loan_security_type_dashboard.py index 7a2732e3190..2a9ceed2d8c 100644 --- a/erpnext/loan_management/doctype/loan_security_type/loan_security_type_dashboard.py +++ b/erpnext/loan_management/doctype/loan_security_type/loan_security_type_dashboard.py @@ -1,6 +1,3 @@ -from __future__ import unicode_literals - - def get_data(): return { 'fieldname': 'loan_security_type', diff --git a/erpnext/loan_management/doctype/loan_security_type/test_loan_security_type.py b/erpnext/loan_management/doctype/loan_security_type/test_loan_security_type.py index 99d7aafb343..cf7a335a774 100644 --- a/erpnext/loan_management/doctype/loan_security_type/test_loan_security_type.py +++ b/erpnext/loan_management/doctype/loan_security_type/test_loan_security_type.py @@ -1,7 +1,5 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2019, Frappe Technologies Pvt. Ltd. and Contributors # See license.txt -from __future__ import unicode_literals # import frappe import unittest diff --git a/erpnext/loan_management/doctype/loan_security_unpledge/loan_security_unpledge.py b/erpnext/loan_management/doctype/loan_security_unpledge/loan_security_unpledge.py index 0af0de1a53a..bff9d5cf62d 100644 --- a/erpnext/loan_management/doctype/loan_security_unpledge/loan_security_unpledge.py +++ b/erpnext/loan_management/doctype/loan_security_unpledge/loan_security_unpledge.py @@ -1,14 +1,11 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2019, Frappe Technologies Pvt. Ltd. and contributors # For license information, please see license.txt -from __future__ import unicode_literals import frappe from frappe import _ from frappe.model.document import Document from frappe.utils import flt, get_datetime, getdate -from six import iteritems class LoanSecurityUnpledge(Document): @@ -111,7 +108,7 @@ class LoanSecurityUnpledge(Document): pledged_qty = 0 current_pledges = get_pledged_security_qty(self.loan) - for security, qty in iteritems(current_pledges): + for security, qty in current_pledges.items(): pledged_qty += qty if not pledged_qty: @@ -144,7 +141,7 @@ def get_pledged_security_qty(loan): GROUP BY p.loan_security """, (loan))) - for security, qty in iteritems(pledges): + for security, qty in pledges.items(): current_pledges.setdefault(security, qty) current_pledges[security] -= unpledges.get(security, 0.0) diff --git a/erpnext/loan_management/doctype/loan_security_unpledge/test_loan_security_unpledge.py b/erpnext/loan_management/doctype/loan_security_unpledge/test_loan_security_unpledge.py index 17eb7c63c7a..2f124e4965f 100644 --- a/erpnext/loan_management/doctype/loan_security_unpledge/test_loan_security_unpledge.py +++ b/erpnext/loan_management/doctype/loan_security_unpledge/test_loan_security_unpledge.py @@ -1,7 +1,5 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2019, Frappe Technologies Pvt. Ltd. and Contributors # See license.txt -from __future__ import unicode_literals # import frappe import unittest diff --git a/erpnext/loan_management/doctype/loan_type/loan_type.py b/erpnext/loan_management/doctype/loan_type/loan_type.py index 5458d358f3b..592229cf994 100644 --- a/erpnext/loan_management/doctype/loan_type/loan_type.py +++ b/erpnext/loan_management/doctype/loan_type/loan_type.py @@ -1,8 +1,6 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2019, Frappe Technologies Pvt. Ltd. and contributors # For license information, please see license.txt -from __future__ import unicode_literals import frappe from frappe import _ diff --git a/erpnext/loan_management/doctype/loan_type/loan_type_dashboard.py b/erpnext/loan_management/doctype/loan_type/loan_type_dashboard.py index 96b2c4aedcf..245e1021202 100644 --- a/erpnext/loan_management/doctype/loan_type/loan_type_dashboard.py +++ b/erpnext/loan_management/doctype/loan_type/loan_type_dashboard.py @@ -1,6 +1,3 @@ -from __future__ import unicode_literals - - def get_data(): return { 'fieldname': 'loan_type', diff --git a/erpnext/loan_management/doctype/loan_type/test_loan_type.py b/erpnext/loan_management/doctype/loan_type/test_loan_type.py index 9e57fdef2fa..e3b51e8f7d2 100644 --- a/erpnext/loan_management/doctype/loan_type/test_loan_type.py +++ b/erpnext/loan_management/doctype/loan_type/test_loan_type.py @@ -1,7 +1,5 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2019, Frappe Technologies Pvt. Ltd. and Contributors # See license.txt -from __future__ import unicode_literals # import frappe import unittest diff --git a/erpnext/loan_management/doctype/loan_write_off/loan_write_off.py b/erpnext/loan_management/doctype/loan_write_off/loan_write_off.py index 4d5e7df4de1..35be587f87f 100644 --- a/erpnext/loan_management/doctype/loan_write_off/loan_write_off.py +++ b/erpnext/loan_management/doctype/loan_write_off/loan_write_off.py @@ -1,8 +1,6 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2020, Frappe Technologies Pvt. Ltd. and contributors # For license information, please see license.txt -from __future__ import unicode_literals import frappe from frappe import _ diff --git a/erpnext/loan_management/doctype/loan_write_off/test_loan_write_off.py b/erpnext/loan_management/doctype/loan_write_off/test_loan_write_off.py index 57337c7e5d2..1494114afb3 100644 --- a/erpnext/loan_management/doctype/loan_write_off/test_loan_write_off.py +++ b/erpnext/loan_management/doctype/loan_write_off/test_loan_write_off.py @@ -1,7 +1,5 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2020, Frappe Technologies Pvt. Ltd. and Contributors # See license.txt -from __future__ import unicode_literals # import frappe import unittest diff --git a/erpnext/loan_management/doctype/pledge/pledge.py b/erpnext/loan_management/doctype/pledge/pledge.py index 5a41cde4b58..f02ed95275d 100644 --- a/erpnext/loan_management/doctype/pledge/pledge.py +++ b/erpnext/loan_management/doctype/pledge/pledge.py @@ -1,8 +1,6 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2019, Frappe Technologies Pvt. Ltd. and contributors # For license information, please see license.txt -from __future__ import unicode_literals # import frappe from frappe.model.document import Document diff --git a/erpnext/loan_management/doctype/pledge/test_pledge.py b/erpnext/loan_management/doctype/pledge/test_pledge.py index adcbc6eae03..2d3fd320f5b 100644 --- a/erpnext/loan_management/doctype/pledge/test_pledge.py +++ b/erpnext/loan_management/doctype/pledge/test_pledge.py @@ -1,7 +1,5 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2019, Frappe Technologies Pvt. Ltd. and Contributors # See license.txt -from __future__ import unicode_literals # import frappe import unittest diff --git a/erpnext/loan_management/doctype/process_loan_interest_accrual/process_loan_interest_accrual.py b/erpnext/loan_management/doctype/process_loan_interest_accrual/process_loan_interest_accrual.py index efee701dc04..4c34ccd983e 100644 --- a/erpnext/loan_management/doctype/process_loan_interest_accrual/process_loan_interest_accrual.py +++ b/erpnext/loan_management/doctype/process_loan_interest_accrual/process_loan_interest_accrual.py @@ -1,8 +1,6 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2019, Frappe Technologies Pvt. Ltd. and contributors # For license information, please see license.txt -from __future__ import unicode_literals import frappe from frappe.model.document import Document diff --git a/erpnext/loan_management/doctype/process_loan_interest_accrual/process_loan_interest_accrual_dashboard.py b/erpnext/loan_management/doctype/process_loan_interest_accrual/process_loan_interest_accrual_dashboard.py index fcd0399c6e9..932087cb5a1 100644 --- a/erpnext/loan_management/doctype/process_loan_interest_accrual/process_loan_interest_accrual_dashboard.py +++ b/erpnext/loan_management/doctype/process_loan_interest_accrual/process_loan_interest_accrual_dashboard.py @@ -1,6 +1,3 @@ -from __future__ import unicode_literals - - def get_data(): return { 'fieldname': 'process_loan_interest_accrual', diff --git a/erpnext/loan_management/doctype/process_loan_interest_accrual/test_process_loan_interest_accrual.py b/erpnext/loan_management/doctype/process_loan_interest_accrual/test_process_loan_interest_accrual.py index e7d360209ca..1fb8c2e9529 100644 --- a/erpnext/loan_management/doctype/process_loan_interest_accrual/test_process_loan_interest_accrual.py +++ b/erpnext/loan_management/doctype/process_loan_interest_accrual/test_process_loan_interest_accrual.py @@ -1,7 +1,5 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2019, Frappe Technologies Pvt. Ltd. and Contributors # See license.txt -from __future__ import unicode_literals # import frappe import unittest diff --git a/erpnext/loan_management/doctype/process_loan_security_shortfall/process_loan_security_shortfall.py b/erpnext/loan_management/doctype/process_loan_security_shortfall/process_loan_security_shortfall.py index c3f59543c4e..ba9fb0c449f 100644 --- a/erpnext/loan_management/doctype/process_loan_security_shortfall/process_loan_security_shortfall.py +++ b/erpnext/loan_management/doctype/process_loan_security_shortfall/process_loan_security_shortfall.py @@ -1,8 +1,6 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2019, Frappe Technologies Pvt. Ltd. and contributors # For license information, please see license.txt -from __future__ import unicode_literals import frappe from frappe.model.document import Document diff --git a/erpnext/loan_management/doctype/process_loan_security_shortfall/process_loan_security_shortfall_dashboard.py b/erpnext/loan_management/doctype/process_loan_security_shortfall/process_loan_security_shortfall_dashboard.py index ced3bd7e4fb..1f5d8438ff3 100644 --- a/erpnext/loan_management/doctype/process_loan_security_shortfall/process_loan_security_shortfall_dashboard.py +++ b/erpnext/loan_management/doctype/process_loan_security_shortfall/process_loan_security_shortfall_dashboard.py @@ -1,6 +1,3 @@ -from __future__ import unicode_literals - - def get_data(): return { 'fieldname': 'process_loan_security_shortfall', diff --git a/erpnext/loan_management/doctype/process_loan_security_shortfall/test_process_loan_security_shortfall.py b/erpnext/loan_management/doctype/process_loan_security_shortfall/test_process_loan_security_shortfall.py index 50e0a46ee4f..c743cf05007 100644 --- a/erpnext/loan_management/doctype/process_loan_security_shortfall/test_process_loan_security_shortfall.py +++ b/erpnext/loan_management/doctype/process_loan_security_shortfall/test_process_loan_security_shortfall.py @@ -1,7 +1,5 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2019, Frappe Technologies Pvt. Ltd. and Contributors # See license.txt -from __future__ import unicode_literals # import frappe import unittest diff --git a/erpnext/loan_management/doctype/proposed_pledge/proposed_pledge.py b/erpnext/loan_management/doctype/proposed_pledge/proposed_pledge.py index 5c125e1307e..ac2b7d24012 100644 --- a/erpnext/loan_management/doctype/proposed_pledge/proposed_pledge.py +++ b/erpnext/loan_management/doctype/proposed_pledge/proposed_pledge.py @@ -1,8 +1,6 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2019, Frappe Technologies Pvt. Ltd. and contributors # For license information, please see license.txt -from __future__ import unicode_literals # import frappe from frappe.model.document import Document diff --git a/erpnext/loan_management/doctype/repayment_schedule/repayment_schedule.py b/erpnext/loan_management/doctype/repayment_schedule/repayment_schedule.py index af9c6696aca..dc407e7d99f 100644 --- a/erpnext/loan_management/doctype/repayment_schedule/repayment_schedule.py +++ b/erpnext/loan_management/doctype/repayment_schedule/repayment_schedule.py @@ -1,8 +1,6 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2019, Frappe Technologies Pvt. Ltd. and contributors # For license information, please see license.txt -from __future__ import unicode_literals # import frappe from frappe.model.document import Document diff --git a/erpnext/loan_management/doctype/salary_slip_loan/salary_slip_loan.py b/erpnext/loan_management/doctype/salary_slip_loan/salary_slip_loan.py index 64be1b2673e..91267b80ba1 100644 --- a/erpnext/loan_management/doctype/salary_slip_loan/salary_slip_loan.py +++ b/erpnext/loan_management/doctype/salary_slip_loan/salary_slip_loan.py @@ -1,8 +1,6 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2019, Frappe Technologies Pvt. Ltd. and contributors # For license information, please see license.txt -from __future__ import unicode_literals # import frappe from frappe.model.document import Document diff --git a/erpnext/loan_management/doctype/sanctioned_loan_amount/sanctioned_loan_amount.py b/erpnext/loan_management/doctype/sanctioned_loan_amount/sanctioned_loan_amount.py index 5660c421022..6063b7bad8b 100644 --- a/erpnext/loan_management/doctype/sanctioned_loan_amount/sanctioned_loan_amount.py +++ b/erpnext/loan_management/doctype/sanctioned_loan_amount/sanctioned_loan_amount.py @@ -1,8 +1,6 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2019, Frappe Technologies Pvt. Ltd. and contributors # For license information, please see license.txt -from __future__ import unicode_literals import frappe from frappe import _ diff --git a/erpnext/loan_management/doctype/sanctioned_loan_amount/test_sanctioned_loan_amount.py b/erpnext/loan_management/doctype/sanctioned_loan_amount/test_sanctioned_loan_amount.py index 663f2e72beb..4d99086d612 100644 --- a/erpnext/loan_management/doctype/sanctioned_loan_amount/test_sanctioned_loan_amount.py +++ b/erpnext/loan_management/doctype/sanctioned_loan_amount/test_sanctioned_loan_amount.py @@ -1,7 +1,5 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2019, Frappe Technologies Pvt. Ltd. and Contributors # See license.txt -from __future__ import unicode_literals # import frappe import unittest diff --git a/erpnext/loan_management/doctype/unpledge/unpledge.py b/erpnext/loan_management/doctype/unpledge/unpledge.py index 2e82e239979..403749ba646 100644 --- a/erpnext/loan_management/doctype/unpledge/unpledge.py +++ b/erpnext/loan_management/doctype/unpledge/unpledge.py @@ -1,8 +1,6 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2019, Frappe Technologies Pvt. Ltd. and contributors # For license information, please see license.txt -from __future__ import unicode_literals # import frappe from frappe.model.document import Document diff --git a/erpnext/loan_management/report/applicant_wise_loan_security_exposure/applicant_wise_loan_security_exposure.py b/erpnext/loan_management/report/applicant_wise_loan_security_exposure/applicant_wise_loan_security_exposure.py index ff527029f67..512b47f7991 100644 --- a/erpnext/loan_management/report/applicant_wise_loan_security_exposure/applicant_wise_loan_security_exposure.py +++ b/erpnext/loan_management/report/applicant_wise_loan_security_exposure/applicant_wise_loan_security_exposure.py @@ -1,12 +1,10 @@ # Copyright (c) 2013, Frappe Technologies Pvt. Ltd. and contributors # For license information, please see license.txt -from __future__ import unicode_literals import frappe from frappe import _ from frappe.utils import flt -from six import iteritems import erpnext @@ -45,7 +43,7 @@ def get_data(filters): currency = erpnext.get_company_currency(filters.get('company')) - for key, qty in iteritems(pledge_values): + for key, qty in pledge_values.items(): if qty: row = {} current_value = flt(qty * loan_security_details.get(key[1], {}).get('latest_price', 0)) diff --git a/erpnext/loan_management/report/loan_interest_report/loan_interest_report.py b/erpnext/loan_management/report/loan_interest_report/loan_interest_report.py index c4adef1c7ba..7c512679567 100644 --- a/erpnext/loan_management/report/loan_interest_report/loan_interest_report.py +++ b/erpnext/loan_management/report/loan_interest_report/loan_interest_report.py @@ -1,7 +1,6 @@ # Copyright (c) 2013, Frappe Technologies Pvt. Ltd. and contributors # For license information, please see license.txt -from __future__ import unicode_literals import frappe from frappe import _ diff --git a/erpnext/loan_management/report/loan_repayment_and_closure/loan_repayment_and_closure.py b/erpnext/loan_management/report/loan_repayment_and_closure/loan_repayment_and_closure.py index 9d8a425b30c..68fd3d8e8b5 100644 --- a/erpnext/loan_management/report/loan_repayment_and_closure/loan_repayment_and_closure.py +++ b/erpnext/loan_management/report/loan_repayment_and_closure/loan_repayment_and_closure.py @@ -1,7 +1,6 @@ # Copyright (c) 2013, Frappe Technologies Pvt. Ltd. and contributors # For license information, please see license.txt -from __future__ import unicode_literals import frappe from frappe import _ diff --git a/erpnext/loan_management/report/loan_security_exposure/loan_security_exposure.py b/erpnext/loan_management/report/loan_security_exposure/loan_security_exposure.py index 3d6242a4fa1..7dbb9662339 100644 --- a/erpnext/loan_management/report/loan_security_exposure/loan_security_exposure.py +++ b/erpnext/loan_management/report/loan_security_exposure/loan_security_exposure.py @@ -1,11 +1,9 @@ # Copyright (c) 2013, Frappe Technologies Pvt. Ltd. and contributors # For license information, please see license.txt -from __future__ import unicode_literals from frappe import _ from frappe.utils import flt -from six import iteritems import erpnext from erpnext.loan_management.report.applicant_wise_loan_security_exposure.applicant_wise_loan_security_exposure import ( @@ -44,7 +42,7 @@ def get_data(filters): current_pledges, total_portfolio_value = get_company_wise_loan_security_details(filters, loan_security_details) currency = erpnext.get_company_currency(filters.get('company')) - for security, value in iteritems(current_pledges): + for security, value in current_pledges.items(): if value.get('qty'): row = {} current_value = flt(value.get('qty', 0) * loan_security_details.get(security, {}).get('latest_price', 0)) @@ -71,7 +69,7 @@ def get_company_wise_loan_security_details(filters, loan_security_details): total_portfolio_value = 0 security_wise_map = {} - for key, qty in iteritems(pledge_values): + for key, qty in pledge_values.items(): security_wise_map.setdefault(key[1], { 'qty': 0.0, 'applicant_count': 0.0 diff --git a/erpnext/loan_management/report/loan_security_status/loan_security_status.py b/erpnext/loan_management/report/loan_security_status/loan_security_status.py index a93a381eb3f..b7e716880e9 100644 --- a/erpnext/loan_management/report/loan_security_status/loan_security_status.py +++ b/erpnext/loan_management/report/loan_security_status/loan_security_status.py @@ -1,7 +1,6 @@ # Copyright (c) 2013, Frappe Technologies Pvt. Ltd. and contributors # For license information, please see license.txt -from __future__ import unicode_literals import frappe from frappe import _ diff --git a/erpnext/loan_management/workspace/loan_management/loan_management.json b/erpnext/loan_management/workspace/loan_management/loan_management.json index ca528ec6bd9..7deee0d4612 100644 --- a/erpnext/loan_management/workspace/loan_management/loan_management.json +++ b/erpnext/loan_management/workspace/loan_management/loan_management.json @@ -1,20 +1,13 @@ { - "category": "", "charts": [], "content": "[{\"type\": \"header\", \"data\": {\"text\": \"Your Shortcuts\", \"level\": 4, \"col\": 12}}, {\"type\": \"shortcut\", \"data\": {\"shortcut_name\": \"Loan Application\", \"col\": 4}}, {\"type\": \"shortcut\", \"data\": {\"shortcut_name\": \"Loan\", \"col\": 4}}, {\"type\": \"shortcut\", \"data\": {\"shortcut_name\": \"Dashboard\", \"col\": 4}}, {\"type\": \"spacer\", \"data\": {\"col\": 12}}, {\"type\": \"header\", \"data\": {\"text\": \"Reports & Masters\", \"level\": 4, \"col\": 12}}, {\"type\": \"card\", \"data\": {\"card_name\": \"Loan\", \"col\": 4}}, {\"type\": \"card\", \"data\": {\"card_name\": \"Loan Processes\", \"col\": 4}}, {\"type\": \"card\", \"data\": {\"card_name\": \"Disbursement and Repayment\", \"col\": 4}}, {\"type\": \"card\", \"data\": {\"card_name\": \"Loan Security\", \"col\": 4}}, {\"type\": \"card\", \"data\": {\"card_name\": \"Reports\", \"col\": 4}}]", "creation": "2020-03-12 16:35:55.299820", - "developer_mode_only": 0, - "disable_user_customization": 0, "docstatus": 0, "doctype": "Workspace", - "extends": "", - "extends_another_page": 0, "for_user": "", "hide_custom": 0, "icon": "loan", "idx": 0, - "is_default": 0, - "is_standard": 0, "label": "Loans", "links": [ { @@ -245,15 +238,12 @@ "type": "Link" } ], - "modified": "2021-08-05 12:18:13.350904", + "modified": "2021-08-05 12:18:13.350905", "modified_by": "Administrator", "module": "Loan Management", "name": "Loans", - "onboarding": "", "owner": "Administrator", "parent_page": "", - "pin_to_bottom": 0, - "pin_to_top": 0, "public": 1, "restrict_to_domain": "", "roles": [], diff --git a/erpnext/maintenance/doctype/maintenance_schedule/maintenance_schedule.js b/erpnext/maintenance/doctype/maintenance_schedule/maintenance_schedule.js index d1a8c8de27c..035290d8f19 100644 --- a/erpnext/maintenance/doctype/maintenance_schedule/maintenance_schedule.js +++ b/erpnext/maintenance/doctype/maintenance_schedule/maintenance_schedule.js @@ -18,7 +18,7 @@ frappe.ui.form.on('Maintenance Schedule', { }, refresh: function (frm) { setTimeout(() => { - frm.toggle_display('generate_schedule', !(frm.is_new())); + frm.toggle_display('generate_schedule', !(frm.is_new() || frm.doc.docstatus)); frm.toggle_display('schedule', !(frm.is_new())); }, 10); }, diff --git a/erpnext/maintenance/doctype/maintenance_schedule/maintenance_schedule.py b/erpnext/maintenance/doctype/maintenance_schedule/maintenance_schedule.py index 52e41c5863e..db126cde8e1 100644 --- a/erpnext/maintenance/doctype/maintenance_schedule/maintenance_schedule.py +++ b/erpnext/maintenance/doctype/maintenance_schedule/maintenance_schedule.py @@ -1,7 +1,6 @@ # Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors # License: GNU General Public License v3. See license.txt -from __future__ import unicode_literals import frappe from frappe import _, throw @@ -16,9 +15,9 @@ from erpnext.utilities.transaction_base import TransactionBase, delete_events class MaintenanceSchedule(TransactionBase): @frappe.whitelist() def generate_schedule(self): + if self.docstatus != 0: + return self.set('schedules', []) - frappe.db.sql("""delete from `tabMaintenance Schedule Detail` - where parent=%s""", (self.name)) count = 1 for d in self.get('items'): self.validate_maintenance_detail() @@ -47,7 +46,7 @@ class MaintenanceSchedule(TransactionBase): "Yearly": 365 } for item in self.items: - if item.periodicity and item.start_date: + if item.periodicity and item.periodicity != "Random" and item.start_date: if not item.end_date: if item.no_of_visits: item.end_date = add_days(item.start_date, item.no_of_visits * days_in_period[item.periodicity]) @@ -199,12 +198,16 @@ class MaintenanceSchedule(TransactionBase): if chk: throw(_("Maintenance Schedule {0} exists against {1}").format(chk[0][0], d.sales_order)) + def validate_no_of_visits(self): + return len(self.schedules) != sum(d.no_of_visits for d in self.items) + def validate(self): self.validate_end_date_visits() self.validate_maintenance_detail() self.validate_dates_with_periodicity() self.validate_sales_order() - self.generate_schedule() + if not self.schedules or self.validate_no_of_visits(): + self.generate_schedule() def on_update(self): frappe.db.set(self, 'status', 'Draft') diff --git a/erpnext/maintenance/doctype/maintenance_schedule/test_maintenance_schedule.py b/erpnext/maintenance/doctype/maintenance_schedule/test_maintenance_schedule.py index 38654de6638..37ea3fdac30 100644 --- a/erpnext/maintenance/doctype/maintenance_schedule/test_maintenance_schedule.py +++ b/erpnext/maintenance/doctype/maintenance_schedule/test_maintenance_schedule.py @@ -1,7 +1,5 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors # See license.txt -from __future__ import unicode_literals import unittest diff --git a/erpnext/maintenance/doctype/maintenance_schedule_detail/maintenance_schedule_detail.json b/erpnext/maintenance/doctype/maintenance_schedule_detail/maintenance_schedule_detail.json index 8ccef6a8172..afe273f3102 100644 --- a/erpnext/maintenance/doctype/maintenance_schedule_detail/maintenance_schedule_detail.json +++ b/erpnext/maintenance/doctype/maintenance_schedule_detail/maintenance_schedule_detail.json @@ -89,13 +89,14 @@ "width": "160px" }, { + "allow_on_submit": 1, "columns": 2, + "default": "Pending", "fieldname": "completion_status", "fieldtype": "Select", "in_list_view": 1, "label": "Completion Status", - "options": "Pending\nPartially Completed\nFully Completed", - "read_only": 1 + "options": "Pending\nPartially Completed\nFully Completed" }, { "fieldname": "column_break_3", @@ -125,10 +126,11 @@ "idx": 1, "istable": 1, "links": [], - "modified": "2021-05-27 16:07:25.905015", + "modified": "2021-09-16 21:25:22.506485", "modified_by": "Administrator", "module": "Maintenance", "name": "Maintenance Schedule Detail", + "naming_rule": "Random", "owner": "Administrator", "permissions": [], "sort_field": "modified", diff --git a/erpnext/maintenance/doctype/maintenance_schedule_detail/maintenance_schedule_detail.py b/erpnext/maintenance/doctype/maintenance_schedule_detail/maintenance_schedule_detail.py index 27c95a1ea2b..cb20066da04 100644 --- a/erpnext/maintenance/doctype/maintenance_schedule_detail/maintenance_schedule_detail.py +++ b/erpnext/maintenance/doctype/maintenance_schedule_detail/maintenance_schedule_detail.py @@ -1,8 +1,6 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and contributors # For license information, please see license.txt -from __future__ import unicode_literals from frappe.model.document import Document diff --git a/erpnext/maintenance/doctype/maintenance_schedule_item/maintenance_schedule_item.py b/erpnext/maintenance/doctype/maintenance_schedule_item/maintenance_schedule_item.py index 9c4a690789d..b6ce0a50f17 100644 --- a/erpnext/maintenance/doctype/maintenance_schedule_item/maintenance_schedule_item.py +++ b/erpnext/maintenance/doctype/maintenance_schedule_item/maintenance_schedule_item.py @@ -1,8 +1,6 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and contributors # For license information, please see license.txt -from __future__ import unicode_literals from frappe.model.document import Document diff --git a/erpnext/maintenance/doctype/maintenance_visit/maintenance_visit.js b/erpnext/maintenance/doctype/maintenance_visit/maintenance_visit.js index 6b3f18484ad..7f983541f6d 100644 --- a/erpnext/maintenance/doctype/maintenance_visit/maintenance_visit.js +++ b/erpnext/maintenance/doctype/maintenance_visit/maintenance_visit.js @@ -31,8 +31,8 @@ frappe.ui.form.on('Maintenance Visit', { }, onload: function (frm, cdt, cdn) { let item = locals[cdt][cdn]; - if (frm.maintenance_type == 'Scheduled') { - let schedule_id = item.purposes[0].prevdoc_detail_docname; + if (frm.doc.maintenance_type === "Scheduled") { + const schedule_id = item.purposes[0].prevdoc_detail_docname || frm.doc.maintenance_schedule_detail; frappe.call({ method: "erpnext.maintenance.doctype.maintenance_schedule.maintenance_schedule.update_serial_nos", args: { @@ -43,6 +43,9 @@ frappe.ui.form.on('Maintenance Visit', { } }); } + else { + frm.clear_table("purposes"); + } if (!frm.doc.status) { frm.set_value({ status: 'Draft' }); diff --git a/erpnext/maintenance/doctype/maintenance_visit/maintenance_visit.py b/erpnext/maintenance/doctype/maintenance_visit/maintenance_visit.py index 814ec0cae4b..5a87b162af6 100644 --- a/erpnext/maintenance/doctype/maintenance_visit/maintenance_visit.py +++ b/erpnext/maintenance/doctype/maintenance_visit/maintenance_visit.py @@ -1,7 +1,6 @@ # Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors # License: GNU General Public License v3. See license.txt -from __future__ import unicode_literals import frappe from frappe import _ diff --git a/erpnext/maintenance/doctype/maintenance_visit/test_maintenance_visit.py b/erpnext/maintenance/doctype/maintenance_visit/test_maintenance_visit.py index 57e728d1b13..6a9e70a1a92 100644 --- a/erpnext/maintenance/doctype/maintenance_visit/test_maintenance_visit.py +++ b/erpnext/maintenance/doctype/maintenance_visit/test_maintenance_visit.py @@ -1,11 +1,41 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors # See license.txt -from __future__ import unicode_literals import unittest +import frappe +from frappe.utils.data import today + # test_records = frappe.get_test_records('Maintenance Visit') class TestMaintenanceVisit(unittest.TestCase): pass + +def make_maintenance_visit(): + mv = frappe.new_doc("Maintenance Visit") + mv.company = "_Test Company" + mv.customer = "_Test Customer" + mv.mntc_date = today() + mv.completion_status = "Partially Completed" + + sales_person = make_sales_person("Dwight Schrute") + + mv.append("purposes", { + "item_code": "_Test Item", + "sales_person": "Sales Team", + "description": "Test Item", + "work_done": "Test Work Done", + "service_person": sales_person.name + }) + mv.insert(ignore_permissions=True) + + return mv + +def make_sales_person(name): + sales_person = frappe.get_doc({ + 'doctype': "Sales Person", + 'sales_person_name': name + }) + sales_person.insert(ignore_if_duplicate = True) + + return sales_person diff --git a/erpnext/maintenance/doctype/maintenance_visit_purpose/maintenance_visit_purpose.py b/erpnext/maintenance/doctype/maintenance_visit_purpose/maintenance_visit_purpose.py index 4c59562685d..50d9a4e08af 100644 --- a/erpnext/maintenance/doctype/maintenance_visit_purpose/maintenance_visit_purpose.py +++ b/erpnext/maintenance/doctype/maintenance_visit_purpose/maintenance_visit_purpose.py @@ -1,8 +1,6 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and contributors # For license information, please see license.txt -from __future__ import unicode_literals from frappe.model.document import Document diff --git a/erpnext/manufacturing/doctype/__init__.py b/erpnext/manufacturing/doctype/__init__.py index baffc488252..e69de29bb2d 100644 --- a/erpnext/manufacturing/doctype/__init__.py +++ b/erpnext/manufacturing/doctype/__init__.py @@ -1 +0,0 @@ -from __future__ import unicode_literals diff --git a/erpnext/manufacturing/doctype/blanket_order/blanket_order.py b/erpnext/manufacturing/doctype/blanket_order/blanket_order.py index 59eb168d4e4..5340c51131f 100644 --- a/erpnext/manufacturing/doctype/blanket_order/blanket_order.py +++ b/erpnext/manufacturing/doctype/blanket_order/blanket_order.py @@ -1,8 +1,6 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2018, Frappe Technologies Pvt. Ltd. and contributors # For license information, please see license.txt -from __future__ import unicode_literals import frappe from frappe import _ diff --git a/erpnext/manufacturing/doctype/blanket_order/blanket_order_dashboard.py b/erpnext/manufacturing/doctype/blanket_order/blanket_order_dashboard.py index 83260ec1b9f..c6745c877ca 100644 --- a/erpnext/manufacturing/doctype/blanket_order/blanket_order_dashboard.py +++ b/erpnext/manufacturing/doctype/blanket_order/blanket_order_dashboard.py @@ -1,6 +1,3 @@ -from __future__ import unicode_literals - - def get_data(): return { 'fieldname': 'blanket_order', diff --git a/erpnext/manufacturing/doctype/blanket_order/test_blanket_order.py b/erpnext/manufacturing/doctype/blanket_order/test_blanket_order.py index 3104ae01177..d5db3fc1ccf 100644 --- a/erpnext/manufacturing/doctype/blanket_order/test_blanket_order.py +++ b/erpnext/manufacturing/doctype/blanket_order/test_blanket_order.py @@ -1,7 +1,5 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2018, Frappe Technologies Pvt. Ltd. and Contributors # See license.txt -from __future__ import unicode_literals import unittest diff --git a/erpnext/manufacturing/doctype/blanket_order_item/blanket_order_item.py b/erpnext/manufacturing/doctype/blanket_order_item/blanket_order_item.py index 0825f763dcf..ebce209fbc2 100644 --- a/erpnext/manufacturing/doctype/blanket_order_item/blanket_order_item.py +++ b/erpnext/manufacturing/doctype/blanket_order_item/blanket_order_item.py @@ -1,8 +1,6 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2018, Frappe Technologies Pvt. Ltd. and contributors # For license information, please see license.txt -from __future__ import unicode_literals from frappe.model.document import Document diff --git a/erpnext/manufacturing/doctype/bom/__init__.py b/erpnext/manufacturing/doctype/bom/__init__.py index baffc488252..e69de29bb2d 100644 --- a/erpnext/manufacturing/doctype/bom/__init__.py +++ b/erpnext/manufacturing/doctype/bom/__init__.py @@ -1 +0,0 @@ -from __future__ import unicode_literals diff --git a/erpnext/manufacturing/doctype/bom/bom.js b/erpnext/manufacturing/doctype/bom/bom.js index 8a9241391ab..6d35d65bea9 100644 --- a/erpnext/manufacturing/doctype/bom/bom.js +++ b/erpnext/manufacturing/doctype/bom/bom.js @@ -215,7 +215,32 @@ frappe.ui.form.on("BOM", { label: __('Qty To Manufacture'), fieldname: 'qty', reqd: 1, - default: 1 + default: 1, + onchange: () => { + const { quantity, items: rm } = frm.doc; + const variant_items_map = rm.reduce((acc, item) => { + acc[item.item_code] = item.qty; + return acc; + }, {}); + const mf_qty = cur_dialog.fields_list.filter( + (f) => f.df.fieldname === "qty" + )[0]?.value; + const items = cur_dialog.fields.filter( + (f) => f.fieldname === "items" + )[0]?.data; + + if (!items) { + return; + } + + items.forEach((item) => { + item.qty = + (variant_items_map[item.item_code] * mf_qty) / + quantity; + }); + + cur_dialog.refresh(); + } }); } @@ -655,12 +680,6 @@ frappe.ui.form.on("BOM Item", "items_remove", function(frm) { erpnext.bom.calculate_total(frm.doc); }); -frappe.ui.form.on("BOM", "with_operations", function(frm) { - if(!cint(frm.doc.with_operations)) { - frm.set_value("operations", []); - } -}); - frappe.tour['BOM'] = [ { fieldname: "item", diff --git a/erpnext/manufacturing/doctype/bom/bom.json b/erpnext/manufacturing/doctype/bom/bom.json index 7e539183b0c..218ac64d8da 100644 --- a/erpnext/manufacturing/doctype/bom/bom.json +++ b/erpnext/manufacturing/doctype/bom/bom.json @@ -237,6 +237,7 @@ "options": "Price List" }, { + "depends_on": "with_operations", "fieldname": "operations_section", "fieldtype": "Section Break", "hide_border": 1, @@ -436,7 +437,7 @@ "description": "Item Image (if not slideshow)", "fieldname": "website_image", "fieldtype": "Attach Image", - "label": "Image" + "label": "Website Image" }, { "allow_on_submit": 1, @@ -539,7 +540,7 @@ "image_field": "image", "is_submittable": 1, "links": [], - "modified": "2021-05-16 12:25:09.081968", + "modified": "2021-11-18 13:04:16.271975", "modified_by": "Administrator", "module": "Manufacturing", "name": "BOM", diff --git a/erpnext/manufacturing/doctype/bom/bom.py b/erpnext/manufacturing/doctype/bom/bom.py index 28a84b25062..2cd8f8c15af 100644 --- a/erpnext/manufacturing/doctype/bom/bom.py +++ b/erpnext/manufacturing/doctype/bom/bom.py @@ -307,6 +307,9 @@ class BOM(WebsiteGenerator): existing_bom_cost = self.total_cost for d in self.get("items"): + if not d.item_code: + continue + rate = self.get_rm_rate({ "company": self.company, "item_code": d.item_code, @@ -510,8 +513,14 @@ class BOM(WebsiteGenerator): if d.workstation: self.update_rate_and_time(d, update_hour_rate) - self.operating_cost += flt(d.operating_cost) - self.base_operating_cost += flt(d.base_operating_cost) + operating_cost = d.operating_cost + base_operating_cost = d.base_operating_cost + if d.set_cost_based_on_bom_qty: + operating_cost = flt(d.cost_per_unit) * flt(self.quantity) + base_operating_cost = flt(d.base_cost_per_unit) * flt(self.quantity) + + self.operating_cost += flt(operating_cost) + self.base_operating_cost += flt(base_operating_cost) def update_rate_and_time(self, row, update_hour_rate = False): if not row.hour_rate or update_hour_rate: @@ -535,6 +544,8 @@ class BOM(WebsiteGenerator): row.base_hour_rate = flt(row.hour_rate) * flt(self.conversion_rate) row.operating_cost = flt(row.hour_rate) * flt(row.time_in_mins) / 60.0 row.base_operating_cost = flt(row.operating_cost) * flt(self.conversion_rate) + row.cost_per_unit = row.operating_cost / (row.batch_size or 1.0) + row.base_cost_per_unit = row.base_operating_cost / (row.batch_size or 1.0) if update_hour_rate: row.db_update() @@ -591,7 +602,7 @@ class BOM(WebsiteGenerator): for d in self.get('items'): if d.bom_no: self.get_child_exploded_items(d.bom_no, d.stock_qty) - else: + elif d.item_code: self.add_to_cur_exploded_items(frappe._dict({ 'item_code' : d.item_code, 'item_name' : d.item_name, diff --git a/erpnext/manufacturing/doctype/bom/bom_dashboard.py b/erpnext/manufacturing/doctype/bom/bom_dashboard.py index f65df011a93..0699f74aad9 100644 --- a/erpnext/manufacturing/doctype/bom/bom_dashboard.py +++ b/erpnext/manufacturing/doctype/bom/bom_dashboard.py @@ -1,5 +1,3 @@ -from __future__ import unicode_literals - from frappe import _ diff --git a/erpnext/manufacturing/doctype/bom/bom_item_preview.html b/erpnext/manufacturing/doctype/bom/bom_item_preview.html index e614a7ebaa1..eb4135e03ac 100644 --- a/erpnext/manufacturing/doctype/bom/bom_item_preview.html +++ b/erpnext/manufacturing/doctype/bom/bom_item_preview.html @@ -16,26 +16,15 @@

- {% if data.value %} - + {% if data.value && data.value != "BOM" %} + {{ __("Open BOM {0}", [data.value.bold()]) }} {% endif %} {% if data.item_code %} - + {{ __("Open Item {0}", [data.item_code.bold()]) }} {% endif %}

-
-

- {% if data.value %} - - {{ __("Open BOM {0}", [data.value.bold()]) }} - {% endif %} - {% if data.item_code %} - - {{ __("Open Item {0}", [data.item_code.bold()]) }} - {% endif %} -

diff --git a/erpnext/manufacturing/doctype/bom/bom_tree.js b/erpnext/manufacturing/doctype/bom/bom_tree.js index 6e2599e41bc..fb99add12cf 100644 --- a/erpnext/manufacturing/doctype/bom/bom_tree.js +++ b/erpnext/manufacturing/doctype/bom/bom_tree.js @@ -66,6 +66,7 @@ frappe.treeview_settings["BOM"] = { var bom = frappe.model.get_doc("BOM", node.data.value); node.data.image = escape(bom.image) || ""; node.data.description = bom.description || ""; + node.data.item_code = bom.item || ""; }); } }, diff --git a/erpnext/manufacturing/doctype/bom/test_bom.py b/erpnext/manufacturing/doctype/bom/test_bom.py index 7950dd9d972..4c032307d80 100644 --- a/erpnext/manufacturing/doctype/bom/test_bom.py +++ b/erpnext/manufacturing/doctype/bom/test_bom.py @@ -4,13 +4,14 @@ import unittest from collections import deque +from functools import partial import frappe from frappe.test_runner import make_test_records from frappe.utils import cstr, flt from erpnext.buying.doctype.purchase_order.test_purchase_order import create_purchase_order -from erpnext.manufacturing.doctype.bom.bom import make_variant_bom +from erpnext.manufacturing.doctype.bom.bom import item_query, make_variant_bom from erpnext.manufacturing.doctype.bom_update_tool.bom_update_tool import update_cost from erpnext.stock.doctype.item.test_item import make_item from erpnext.stock.doctype.stock_reconciliation.test_stock_reconciliation import ( @@ -108,6 +109,24 @@ class TestBOM(unittest.TestCase): self.assertAlmostEqual(bom.base_raw_material_cost, base_raw_material_cost) self.assertAlmostEqual(bom.base_total_cost, base_raw_material_cost + base_op_cost) + def test_bom_cost_with_batch_size(self): + bom = frappe.copy_doc(test_records[2]) + bom.docstatus = 0 + op_cost = 0.0 + for op_row in bom.operations: + op_row.docstatus = 0 + op_row.batch_size = 2 + op_row.set_cost_based_on_bom_qty = 1 + op_cost += op_row.operating_cost + + bom.save() + + for op_row in bom.operations: + self.assertAlmostEqual(op_row.cost_per_unit, op_row.operating_cost / 2) + + self.assertAlmostEqual(bom.operating_cost, op_cost/2) + bom.delete() + def test_bom_cost_multi_uom_multi_currency_based_on_price_list(self): frappe.db.set_value("Price List", "_Test Price List", "price_not_uom_dependent", 1) for item_code, rate in (("_Test Item", 3600), ("_Test Item Home Desktop Manufactured", 3000)): @@ -357,6 +376,16 @@ class TestBOM(unittest.TestCase): # FG Items in Scrap/Loss Table should have Is Process Loss set self.assertRaises(frappe.ValidationError, bom_doc.submit) + def test_bom_item_query(self): + query = partial(item_query, doctype="Item", txt="", searchfield="name", start=0, page_len=20, filters={"is_stock_item": 1}) + + test_items = query(txt="_Test") + filtered = query(txt="_Test Item 2") + + self.assertNotEqual(len(test_items), len(filtered), msg="Item filtering showing excessive results") + self.assertTrue(0 < len(filtered) <= 3, msg="Item filtering showing excessive results") + + def get_default_bom(item_code="_Test FG Item 2"): return frappe.db.get_value("BOM", {"item": item_code, "is_active": 1, "is_default": 1}) diff --git a/erpnext/manufacturing/doctype/bom_explosion_item/__init__.py b/erpnext/manufacturing/doctype/bom_explosion_item/__init__.py index baffc488252..e69de29bb2d 100644 --- a/erpnext/manufacturing/doctype/bom_explosion_item/__init__.py +++ b/erpnext/manufacturing/doctype/bom_explosion_item/__init__.py @@ -1 +0,0 @@ -from __future__ import unicode_literals diff --git a/erpnext/manufacturing/doctype/bom_explosion_item/bom_explosion_item.py b/erpnext/manufacturing/doctype/bom_explosion_item/bom_explosion_item.py index 4317d3adf68..cbcba345bca 100644 --- a/erpnext/manufacturing/doctype/bom_explosion_item/bom_explosion_item.py +++ b/erpnext/manufacturing/doctype/bom_explosion_item/bom_explosion_item.py @@ -1,7 +1,6 @@ # Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors # License: GNU General Public License v3. See license.txt -from __future__ import unicode_literals from frappe.model.document import Document diff --git a/erpnext/manufacturing/doctype/bom_item/__init__.py b/erpnext/manufacturing/doctype/bom_item/__init__.py index baffc488252..e69de29bb2d 100644 --- a/erpnext/manufacturing/doctype/bom_item/__init__.py +++ b/erpnext/manufacturing/doctype/bom_item/__init__.py @@ -1 +0,0 @@ -from __future__ import unicode_literals diff --git a/erpnext/manufacturing/doctype/bom_item/bom_item.py b/erpnext/manufacturing/doctype/bom_item/bom_item.py index 2954238a571..28a4b201444 100644 --- a/erpnext/manufacturing/doctype/bom_item/bom_item.py +++ b/erpnext/manufacturing/doctype/bom_item/bom_item.py @@ -1,7 +1,6 @@ # Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors # License: GNU General Public License v3. See license.txt -from __future__ import unicode_literals from frappe.model.document import Document diff --git a/erpnext/manufacturing/doctype/bom_operation/__init__.py b/erpnext/manufacturing/doctype/bom_operation/__init__.py index baffc488252..e69de29bb2d 100644 --- a/erpnext/manufacturing/doctype/bom_operation/__init__.py +++ b/erpnext/manufacturing/doctype/bom_operation/__init__.py @@ -1 +0,0 @@ -from __future__ import unicode_literals diff --git a/erpnext/manufacturing/doctype/bom_operation/bom_operation.json b/erpnext/manufacturing/doctype/bom_operation/bom_operation.json index 4458e6db234..ec617f3aaa9 100644 --- a/erpnext/manufacturing/doctype/bom_operation/bom_operation.json +++ b/erpnext/manufacturing/doctype/bom_operation/bom_operation.json @@ -8,15 +8,23 @@ "field_order": [ "sequence_id", "operation", - "workstation", - "description", "col_break1", - "hour_rate", + "workstation", "time_in_mins", - "operating_cost", + "costing_section", + "hour_rate", "base_hour_rate", + "column_break_9", + "operating_cost", "base_operating_cost", + "column_break_11", "batch_size", + "set_cost_based_on_bom_qty", + "cost_per_unit", + "base_cost_per_unit", + "more_information_section", + "description", + "column_break_18", "image" ], "fields": [ @@ -117,13 +125,59 @@ "fieldname": "sequence_id", "fieldtype": "Int", "label": "Sequence ID" + }, + { + "depends_on": "eval:doc.batch_size > 0 && doc.set_cost_based_on_bom_qty", + "fieldname": "cost_per_unit", + "fieldtype": "Float", + "label": "Cost Per Unit", + "no_copy": 1, + "print_hide": 1, + "read_only": 1 + }, + { + "fieldname": "base_cost_per_unit", + "fieldtype": "Float", + "hidden": 1, + "label": "Base Cost Per Unit", + "no_copy": 1, + "print_hide": 1, + "read_only": 1 + }, + { + "fieldname": "costing_section", + "fieldtype": "Section Break", + "label": "Costing" + }, + { + "fieldname": "column_break_11", + "fieldtype": "Column Break" + }, + { + "fieldname": "more_information_section", + "fieldtype": "Section Break", + "label": "More Information" + }, + { + "fieldname": "column_break_18", + "fieldtype": "Column Break" + }, + { + "fieldname": "column_break_9", + "fieldtype": "Column Break" + }, + { + "default": "0", + "fieldname": "set_cost_based_on_bom_qty", + "fieldtype": "Check", + "label": "Set Operating Cost Based On BOM Quantity" } ], "idx": 1, "index_web_pages_for_search": 1, "istable": 1, "links": [], - "modified": "2021-01-12 14:48:09.596843", + "modified": "2021-09-13 16:45:01.092868", "modified_by": "Administrator", "module": "Manufacturing", "name": "BOM Operation", diff --git a/erpnext/manufacturing/doctype/bom_operation/bom_operation.py b/erpnext/manufacturing/doctype/bom_operation/bom_operation.py index 5e46c7ef932..0ddc280ac0e 100644 --- a/erpnext/manufacturing/doctype/bom_operation/bom_operation.py +++ b/erpnext/manufacturing/doctype/bom_operation/bom_operation.py @@ -1,7 +1,6 @@ # Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors # License: GNU General Public License v3. See license.txt -from __future__ import unicode_literals from frappe.model.document import Document diff --git a/erpnext/manufacturing/doctype/bom_scrap_item/bom_scrap_item.py b/erpnext/manufacturing/doctype/bom_scrap_item/bom_scrap_item.py index 891fc53c71e..f400303b95e 100644 --- a/erpnext/manufacturing/doctype/bom_scrap_item/bom_scrap_item.py +++ b/erpnext/manufacturing/doctype/bom_scrap_item/bom_scrap_item.py @@ -1,8 +1,6 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and contributors # For license information, please see license.txt -from __future__ import unicode_literals from frappe.model.document import Document diff --git a/erpnext/manufacturing/doctype/bom_update_tool/bom_update_tool.py b/erpnext/manufacturing/doctype/bom_update_tool/bom_update_tool.py index ed71c6d6d7b..0e3955f5a73 100644 --- a/erpnext/manufacturing/doctype/bom_update_tool/bom_update_tool.py +++ b/erpnext/manufacturing/doctype/bom_update_tool/bom_update_tool.py @@ -1,8 +1,6 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2017, Frappe Technologies Pvt. Ltd. and contributors # For license information, please see license.txt -from __future__ import unicode_literals import json @@ -11,7 +9,6 @@ import frappe from frappe import _ from frappe.model.document import Document from frappe.utils import cstr, flt -from six import string_types from erpnext.manufacturing.doctype.bom.bom import get_boms_in_bottom_up_order @@ -81,7 +78,7 @@ def get_new_bom_unit_cost(bom): @frappe.whitelist() def enqueue_replace_bom(args): - if isinstance(args, string_types): + if isinstance(args, str): args = json.loads(args) frappe.enqueue("erpnext.manufacturing.doctype.bom_update_tool.bom_update_tool.replace_bom", args=args, timeout=40000) diff --git a/erpnext/manufacturing/doctype/bom_update_tool/test_bom_update_tool.py b/erpnext/manufacturing/doctype/bom_update_tool/test_bom_update_tool.py index 88c69ce2a5e..526c243ed78 100644 --- a/erpnext/manufacturing/doctype/bom_update_tool/test_bom_update_tool.py +++ b/erpnext/manufacturing/doctype/bom_update_tool/test_bom_update_tool.py @@ -2,7 +2,6 @@ # License: GNU General Public License v3. See license.txt -from __future__ import unicode_literals import unittest diff --git a/erpnext/manufacturing/doctype/bom_website_item/bom_website_item.py b/erpnext/manufacturing/doctype/bom_website_item/bom_website_item.py index f627b4e5283..33256a3b31d 100644 --- a/erpnext/manufacturing/doctype/bom_website_item/bom_website_item.py +++ b/erpnext/manufacturing/doctype/bom_website_item/bom_website_item.py @@ -1,8 +1,6 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and contributors # For license information, please see license.txt -from __future__ import unicode_literals from frappe.model.document import Document diff --git a/erpnext/manufacturing/doctype/bom_website_operation/bom_website_operation.py b/erpnext/manufacturing/doctype/bom_website_operation/bom_website_operation.py index 5bd8cf568c7..f8e279287a6 100644 --- a/erpnext/manufacturing/doctype/bom_website_operation/bom_website_operation.py +++ b/erpnext/manufacturing/doctype/bom_website_operation/bom_website_operation.py @@ -1,8 +1,6 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and contributors # For license information, please see license.txt -from __future__ import unicode_literals from frappe.model.document import Document diff --git a/erpnext/manufacturing/doctype/downtime_entry/downtime_entry.py b/erpnext/manufacturing/doctype/downtime_entry/downtime_entry.py index 62833d7cd20..460281658a8 100644 --- a/erpnext/manufacturing/doctype/downtime_entry/downtime_entry.py +++ b/erpnext/manufacturing/doctype/downtime_entry/downtime_entry.py @@ -1,8 +1,6 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2020, Frappe Technologies Pvt. Ltd. and contributors # For license information, please see license.txt -from __future__ import unicode_literals from frappe.model.document import Document from frappe.utils import time_diff_in_hours diff --git a/erpnext/manufacturing/doctype/downtime_entry/test_downtime_entry.py b/erpnext/manufacturing/doctype/downtime_entry/test_downtime_entry.py index 37169f4439a..2f99a5cd112 100644 --- a/erpnext/manufacturing/doctype/downtime_entry/test_downtime_entry.py +++ b/erpnext/manufacturing/doctype/downtime_entry/test_downtime_entry.py @@ -1,7 +1,5 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2020, Frappe Technologies Pvt. Ltd. and Contributors # See license.txt -from __future__ import unicode_literals # import frappe import unittest diff --git a/erpnext/manufacturing/doctype/job_card/job_card.js b/erpnext/manufacturing/doctype/job_card/job_card.js index 91eb4a0fa90..453ad50e8e6 100644 --- a/erpnext/manufacturing/doctype/job_card/job_card.js +++ b/erpnext/manufacturing/doctype/job_card/job_card.js @@ -26,15 +26,28 @@ frappe.ui.form.on('Job Card', { refresh: function(frm) { frappe.flags.pause_job = 0; frappe.flags.resume_job = 0; + let has_items = frm.doc.items && frm.doc.items.length; - if(!frm.doc.__islocal && frm.doc.items && frm.doc.items.length) { - if (frm.doc.for_quantity != frm.doc.transferred_qty) { + if (frm.doc.__onload.work_order_closed) { + frm.disable_save(); + return; + } + + if (!frm.doc.__islocal && has_items && frm.doc.docstatus < 2) { + let to_request = frm.doc.for_quantity > frm.doc.transferred_qty; + let excess_transfer_allowed = frm.doc.__onload.job_card_excess_transfer; + + if (to_request || excess_transfer_allowed) { frm.add_custom_button(__("Material Request"), () => { frm.trigger("make_material_request"); }); } - if (frm.doc.for_quantity != frm.doc.transferred_qty) { + // check if any row has untransferred materials + // in case of multiple items in JC + let to_transfer = frm.doc.items.some((row) => row.transferred_qty < row.required_qty); + + if (to_transfer || excess_transfer_allowed) { frm.add_custom_button(__("Material Transfer"), () => { frm.trigger("make_stock_entry"); }).addClass("btn-primary"); diff --git a/erpnext/manufacturing/doctype/job_card/job_card.json b/erpnext/manufacturing/doctype/job_card/job_card.json index 046e2fd1825..6528199d82a 100644 --- a/erpnext/manufacturing/doctype/job_card/job_card.json +++ b/erpnext/manufacturing/doctype/job_card/job_card.json @@ -38,6 +38,8 @@ "total_time_in_mins", "section_break_8", "items", + "scrap_items_section", + "scrap_items", "corrective_operation_section", "for_job_card", "is_corrective_job_card", @@ -185,7 +187,7 @@ "default": "0", "fieldname": "transferred_qty", "fieldtype": "Float", - "label": "Transferred Qty", + "label": "FG Qty from Transferred Raw Materials", "read_only": 1 }, { @@ -392,14 +394,29 @@ "fieldtype": "Link", "label": "Batch No", "options": "Batch" + }, + { + "collapsible": 1, + "fieldname": "scrap_items_section", + "fieldtype": "Section Break", + "label": "Scrap Items" + }, + { + "fieldname": "scrap_items", + "fieldtype": "Table", + "label": "Scrap Items", + "no_copy": 1, + "options": "Job Card Scrap Item", + "print_hide": 1 } ], "is_submittable": 1, "links": [], - "modified": "2021-03-16 15:59:32.766484", + "modified": "2021-11-12 10:15:03.572401", "modified_by": "Administrator", "module": "Manufacturing", "name": "Job Card", + "naming_rule": "By \"Naming Series\" field", "owner": "Administrator", "permissions": [ { diff --git a/erpnext/manufacturing/doctype/job_card/job_card.py b/erpnext/manufacturing/doctype/job_card/job_card.py index 3bf9de2708c..8d00019b7d6 100644 --- a/erpnext/manufacturing/doctype/job_card/job_card.py +++ b/erpnext/manufacturing/doctype/job_card/job_card.py @@ -1,9 +1,5 @@ -# -*- coding: utf-8 -*- -# Copyright (c) 2018, Frappe Technologies Pvt. Ltd. and contributors +# Copyright (c) 2021, Frappe Technologies Pvt. Ltd. and contributors # For license information, please see license.txt - -from __future__ import unicode_literals - import datetime import json @@ -37,6 +33,11 @@ class OperationSequenceError(frappe.ValidationError): pass class JobCardCancelError(frappe.ValidationError): pass class JobCard(Document): + def onload(self): + excess_transfer = frappe.db.get_single_value("Manufacturing Settings", "job_card_excess_transfer") + self.set_onload("job_card_excess_transfer", excess_transfer) + self.set_onload("work_order_closed", self.is_work_order_closed()) + def validate(self): self.validate_time_logs() self.set_status() @@ -44,6 +45,7 @@ class JobCard(Document): self.validate_sequence_id() self.set_sub_operations() self.update_sub_operation_status() + self.validate_work_order() def set_sub_operations(self): if self.operation: @@ -91,7 +93,7 @@ class JobCard(Document): if args.get("employee"): # override capacity for employee production_capacity = 1 - validate_overlap_for = " and jc.employee = %(employee)s " + validate_overlap_for = " and jctl.employee = %(employee)s " extra_cond = '' if check_next_available_slot: @@ -449,6 +451,7 @@ class JobCard(Document): frappe.db.set_value('Job Card Item', row.job_card_item, 'transferred_qty', flt(qty)) def set_transferred_qty(self, update_status=False): + "Set total FG Qty for which RM was transferred." if not self.items: self.transferred_qty = self.for_quantity if self.docstatus == 1 else 0 @@ -457,6 +460,7 @@ class JobCard(Document): return if self.items: + # sum of 'For Quantity' of Stock Entries against JC self.transferred_qty = frappe.db.get_value('Stock Entry', { 'job_card': self.name, 'work_order': self.work_order, @@ -500,11 +504,11 @@ class JobCard(Document): self.status = 'Work In Progress' if (self.docstatus == 1 and - (self.for_quantity == self.transferred_qty or not self.items)): + (self.for_quantity <= self.total_completed_qty or not self.items)): self.status = 'Completed' if self.status != 'Completed': - if self.for_quantity == self.transferred_qty: + if self.for_quantity <= self.transferred_qty: self.status = 'Material Transferred' if update_status: @@ -544,6 +548,18 @@ class JobCard(Document): frappe.throw(_("{0}, complete the operation {1} before the operation {2}.") .format(message, bold(row.operation), bold(self.operation)), OperationSequenceError) + def validate_work_order(self): + if self.is_work_order_closed(): + frappe.throw(_("You can't make any changes to Job Card since Work Order is closed.")) + + def is_work_order_closed(self): + if self.work_order: + status = frappe.get_value('Work Order', self.work_order) + + if status == "Closed": + return True + + return False @frappe.whitelist() def make_time_log(args): @@ -600,7 +616,8 @@ def make_material_request(source_name, target_doc=None): "doctype": "Material Request Item", "field_map": { "required_qty": "qty", - "uom": "stock_uom" + "uom": "stock_uom", + "name": "job_card_item" }, "postprocess": update_item, } @@ -610,15 +627,24 @@ def make_material_request(source_name, target_doc=None): @frappe.whitelist() def make_stock_entry(source_name, target_doc=None): - def update_item(obj, target, source_parent): + def update_item(source, target, source_parent): target.t_warehouse = source_parent.wip_warehouse + if not target.conversion_factor: target.conversion_factor = 1 + pending_rm_qty = flt(source.required_qty) - flt(source.transferred_qty) + if pending_rm_qty > 0: + target.qty = pending_rm_qty + def set_missing_values(source, target): target.purpose = "Material Transfer for Manufacture" target.from_bom = 1 - target.fg_completed_qty = source.get('for_quantity', 0) - source.get('transferred_qty', 0) + + # avoid negative 'For Quantity' + pending_fg_qty = flt(source.get('for_quantity', 0)) - flt(source.get('transferred_qty', 0)) + target.fg_completed_qty = pending_fg_qty if pending_fg_qty > 0 else 0 + target.set_transfer_qty() target.calculate_rate_and_amount() target.set_missing_values() @@ -668,7 +694,7 @@ def get_job_details(start, end, filters=None): conditions = get_filters_cond("Job Card", filters, []) job_cards = frappe.db.sql(""" SELECT `tabJob Card`.name, `tabJob Card`.work_order, - `tabJob Card`.employee_name, `tabJob Card`.status, ifnull(`tabJob Card`.remarks, ''), + `tabJob Card`.status, ifnull(`tabJob Card`.remarks, ''), min(`tabJob Card Time Log`.from_time) as from_time, max(`tabJob Card Time Log`.to_time) as to_time FROM `tabJob Card` , `tabJob Card Time Log` @@ -678,7 +704,7 @@ def get_job_details(start, end, filters=None): for d in job_cards: subject_data = [] - for field in ["name", "work_order", "remarks", "employee_name"]: + for field in ["name", "work_order", "remarks"]: if not d.get(field): continue subject_data.append(d.get(field)) diff --git a/erpnext/manufacturing/doctype/job_card/job_card_dashboard.py b/erpnext/manufacturing/doctype/job_card/job_card_dashboard.py index 3ec6697b9f4..acaa895c1a0 100644 --- a/erpnext/manufacturing/doctype/job_card/job_card_dashboard.py +++ b/erpnext/manufacturing/doctype/job_card/job_card_dashboard.py @@ -1,5 +1,3 @@ -from __future__ import unicode_literals - from frappe import _ diff --git a/erpnext/manufacturing/doctype/job_card/test_job_card.py b/erpnext/manufacturing/doctype/job_card/test_job_card.py index db0e08fcd0a..9b4fc8b8b7a 100644 --- a/erpnext/manufacturing/doctype/job_card/test_job_card.py +++ b/erpnext/manufacturing/doctype/job_card/test_job_card.py @@ -1,78 +1,332 @@ -# -*- coding: utf-8 -*- -# Copyright (c) 2018, Frappe Technologies Pvt. Ltd. and Contributors +# Copyright (c) 2021, Frappe Technologies Pvt. Ltd. and Contributors # See license.txt -from __future__ import unicode_literals - import unittest import frappe from frappe.utils import random_string -from erpnext.manufacturing.doctype.job_card.job_card import OperationMismatchError +from erpnext.manufacturing.doctype.job_card.job_card import OperationMismatchError, OverlapError +from erpnext.manufacturing.doctype.job_card.job_card import ( + make_stock_entry as make_stock_entry_from_jc, +) from erpnext.manufacturing.doctype.work_order.test_work_order import make_wo_order_test_record from erpnext.manufacturing.doctype.workstation.test_workstation import make_workstation +from erpnext.stock.doctype.stock_entry.stock_entry_utils import make_stock_entry class TestJobCard(unittest.TestCase): + def setUp(self): + make_bom_for_jc_tests() + + transfer_material_against, source_warehouse = None, None + + tests_that_skip_setup = ( + "test_job_card_material_transfer_correctness", + ) + tests_that_transfer_against_jc = ( + "test_job_card_multiple_materials_transfer", + "test_job_card_excess_material_transfer", + "test_job_card_partial_material_transfer" + ) + + if self._testMethodName in tests_that_skip_setup: + return + + if self._testMethodName in tests_that_transfer_against_jc: + transfer_material_against = "Job Card" + source_warehouse = "Stores - _TC" + + self.work_order = make_wo_order_test_record( + item="_Test FG Item 2", + qty=2, + transfer_material_against=transfer_material_against, + source_warehouse=source_warehouse + ) + + def tearDown(self): + frappe.db.rollback() + def test_job_card(self): - data = frappe.get_cached_value('BOM', - {'docstatus': 1, 'with_operations': 1, 'company': '_Test Company'}, ['name', 'item']) - if data: - bom, bom_item = data + job_cards = frappe.get_all('Job Card', + filters = {'work_order': self.work_order.name}, fields = ["operation_id", "name"]) - work_order = make_wo_order_test_record(item=bom_item, qty=1, bom_no=bom) + if job_cards: + job_card = job_cards[0] + frappe.db.set_value("Job Card", job_card.name, "operation_row_number", job_card.operation_id) - job_cards = frappe.get_all('Job Card', - filters = {'work_order': work_order.name}, fields = ["operation_id", "name"]) + doc = frappe.get_doc("Job Card", job_card.name) + doc.operation_id = "Test Data" + self.assertRaises(OperationMismatchError, doc.save) - if job_cards: - job_card = job_cards[0] - frappe.db.set_value("Job Card", job_card.name, "operation_row_number", job_card.operation_id) - - doc = frappe.get_doc("Job Card", job_card.name) - doc.operation_id = "Test Data" - self.assertRaises(OperationMismatchError, doc.save) - - for d in job_cards: - frappe.delete_doc("Job Card", d.name) + for d in job_cards: + frappe.delete_doc("Job Card", d.name) def test_job_card_with_different_work_station(self): - data = frappe.get_cached_value('BOM', - {'docstatus': 1, 'with_operations': 1, 'company': '_Test Company'}, ['name', 'item']) + job_cards = frappe.get_all('Job Card', + filters = {'work_order': self.work_order.name}, + fields = ["operation_id", "workstation", "name", "for_quantity"]) - if data: - bom, bom_item = data + job_card = job_cards[0] - work_order = make_wo_order_test_record(item=bom_item, qty=1, bom_no=bom) + if job_card: + workstation = frappe.db.get_value("Workstation", + {"name": ("not in", [job_card.workstation])}, "name") - job_cards = frappe.get_all('Job Card', - filters = {'work_order': work_order.name}, - fields = ["operation_id", "workstation", "name", "for_quantity"]) + if not workstation or job_card.workstation == workstation: + workstation = make_workstation(workstation_name=random_string(5)).name - job_card = job_cards[0] + doc = frappe.get_doc("Job Card", job_card.name) + doc.workstation = workstation + doc.append("time_logs", { + "from_time": "2009-01-01 12:06:25", + "to_time": "2009-01-01 12:37:25", + "time_in_mins": "31.00002", + "completed_qty": job_card.for_quantity + }) + doc.submit() - if job_card: - workstation = frappe.db.get_value("Workstation", - {"name": ("not in", [job_card.workstation])}, "name") + completed_qty = frappe.db.get_value("Work Order Operation", job_card.operation_id, "completed_qty") + self.assertEqual(completed_qty, job_card.for_quantity) - if not workstation or job_card.workstation == workstation: - workstation = make_workstation(workstation_name=random_string(5)).name - - doc = frappe.get_doc("Job Card", job_card.name) - doc.workstation = workstation - doc.append("time_logs", { - "from_time": "2009-01-01 12:06:25", - "to_time": "2009-01-01 12:37:25", - "time_in_mins": "31.00002", - "completed_qty": job_card.for_quantity - }) - doc.submit() - - completed_qty = frappe.db.get_value("Work Order Operation", job_card.operation_id, "completed_qty") - self.assertEqual(completed_qty, job_card.for_quantity) - - doc.cancel() + doc.cancel() for d in job_cards: frappe.delete_doc("Job Card", d.name) + + def test_job_card_overlap(self): + wo2 = make_wo_order_test_record(item="_Test FG Item 2", qty=2) + + jc1_name = frappe.db.get_value("Job Card", {'work_order': self.work_order.name}) + jc2_name = frappe.db.get_value("Job Card", {'work_order': wo2.name}) + + jc1 = frappe.get_doc("Job Card", jc1_name) + jc2 = frappe.get_doc("Job Card", jc2_name) + + employee = "_T-Employee-00001" # from test records + + jc1.append("time_logs", { + "from_time": "2021-01-01 00:00:00", + "to_time": "2021-01-01 08:00:00", + "completed_qty": 1, + "employee": employee, + }) + jc1.save() + + # add a new entry in same time slice + jc2.append("time_logs", { + "from_time": "2021-01-01 00:01:00", + "to_time": "2021-01-01 06:00:00", + "completed_qty": 1, + "employee": employee, + }) + self.assertRaises(OverlapError, jc2.save) + + def test_job_card_multiple_materials_transfer(self): + "Test transferring RMs separately against Job Card with multiple RMs." + make_stock_entry( + item_code="_Test Item", + target="Stores - _TC", + qty=10, + basic_rate=100 + ) + make_stock_entry( + item_code="_Test Item Home Desktop Manufactured", + target="Stores - _TC", + qty=6, + basic_rate=100 + ) + + job_card_name = frappe.db.get_value("Job Card", {'work_order': self.work_order.name}) + job_card = frappe.get_doc("Job Card", job_card_name) + + transfer_entry_1 = make_stock_entry_from_jc(job_card_name) + del transfer_entry_1.items[1] # transfer only 1 of 2 RMs + transfer_entry_1.insert() + transfer_entry_1.submit() + + job_card.reload() + + self.assertEqual(transfer_entry_1.fg_completed_qty, 2) + self.assertEqual(job_card.transferred_qty, 2) + + # transfer second RM + transfer_entry_2 = make_stock_entry_from_jc(job_card_name) + del transfer_entry_2.items[0] + transfer_entry_2.insert() + transfer_entry_2.submit() + + # 'For Quantity' here will be 0 since + # transfer was made for 2 fg qty in first transfer Stock Entry + self.assertEqual(transfer_entry_2.fg_completed_qty, 0) + + def test_job_card_excess_material_transfer(self): + "Test transferring more than required RM against Job Card." + make_stock_entry(item_code="_Test Item", target="Stores - _TC", + qty=25, basic_rate=100) + make_stock_entry(item_code="_Test Item Home Desktop Manufactured", + target="Stores - _TC", qty=15, basic_rate=100) + + job_card_name = frappe.db.get_value("Job Card", {'work_order': self.work_order.name}) + job_card = frappe.get_doc("Job Card", job_card_name) + + # fully transfer both RMs + transfer_entry_1 = make_stock_entry_from_jc(job_card_name) + transfer_entry_1.insert() + transfer_entry_1.submit() + + # transfer extra qty of both RM due to previously damaged RM + transfer_entry_2 = make_stock_entry_from_jc(job_card_name) + # deliberately change 'For Quantity' + transfer_entry_2.fg_completed_qty = 1 + transfer_entry_2.items[0].qty = 5 + transfer_entry_2.items[1].qty = 3 + transfer_entry_2.insert() + transfer_entry_2.submit() + + job_card.reload() + self.assertGreater(job_card.transferred_qty, job_card.for_quantity) + + # Check if 'For Quantity' is negative + # as 'transferred_qty' > Qty to Manufacture + transfer_entry_3 = make_stock_entry_from_jc(job_card_name) + self.assertEqual(transfer_entry_3.fg_completed_qty, 0) + + job_card.append("time_logs", { + "from_time": "2021-01-01 00:01:00", + "to_time": "2021-01-01 06:00:00", + "completed_qty": 2 + }) + job_card.save() + job_card.submit() + + # JC is Completed with excess transfer + self.assertEqual(job_card.status, "Completed") + + def test_job_card_partial_material_transfer(self): + "Test partial material transfer against Job Card" + + make_stock_entry(item_code="_Test Item", target="Stores - _TC", + qty=25, basic_rate=100) + make_stock_entry(item_code="_Test Item Home Desktop Manufactured", + target="Stores - _TC", qty=15, basic_rate=100) + + job_card_name = frappe.db.get_value("Job Card", {'work_order': self.work_order.name}) + job_card = frappe.get_doc("Job Card", job_card_name) + + # partially transfer + transfer_entry = make_stock_entry_from_jc(job_card_name) + transfer_entry.fg_completed_qty = 1 + transfer_entry.get_items() + transfer_entry.insert() + transfer_entry.submit() + + job_card.reload() + self.assertEqual(job_card.transferred_qty, 1) + self.assertEqual(transfer_entry.items[0].qty, 5) + self.assertEqual(transfer_entry.items[1].qty, 3) + + # transfer remaining + transfer_entry_2 = make_stock_entry_from_jc(job_card_name) + + self.assertEqual(transfer_entry_2.fg_completed_qty, 1) + self.assertEqual(transfer_entry_2.items[0].qty, 5) + self.assertEqual(transfer_entry_2.items[1].qty, 3) + + transfer_entry_2.insert() + transfer_entry_2.submit() + + job_card.reload() + self.assertEqual(job_card.transferred_qty, 2) + + def test_job_card_material_transfer_correctness(self): + """ + 1. Test if only current Job Card Items are pulled in a Stock Entry against a Job Card + 2. Test impact of changing 'For Qty' in such a Stock Entry + """ + create_bom_with_multiple_operations() + work_order = make_wo_with_transfer_against_jc() + + job_card_name = frappe.db.get_value( + "Job Card", + {"work_order": work_order.name,"operation": "Test Operation A"} + ) + job_card = frappe.get_doc("Job Card", job_card_name) + + self.assertEqual(len(job_card.items), 1) + self.assertEqual(job_card.items[0].item_code, "_Test Item") + + # check if right items are mapped in transfer entry + transfer_entry = make_stock_entry_from_jc(job_card_name) + transfer_entry.insert() + + self.assertEqual(len(transfer_entry.items), 1) + self.assertEqual(transfer_entry.items[0].item_code, "_Test Item") + self.assertEqual(transfer_entry.items[0].qty, 4) + + # change 'For Qty' and check impact on items table + # no.of items should be the same with qty change + transfer_entry.fg_completed_qty = 2 + transfer_entry.get_items() + + self.assertEqual(len(transfer_entry.items), 1) + self.assertEqual(transfer_entry.items[0].item_code, "_Test Item") + self.assertEqual(transfer_entry.items[0].qty, 2) + + # rollback via tearDown method + +def create_bom_with_multiple_operations(): + "Create a BOM with multiple operations and Material Transfer against Job Card" + from erpnext.manufacturing.doctype.operation.test_operation import make_operation + + test_record = frappe.get_test_records("BOM")[2] + bom_doc = frappe.get_doc(test_record) + + row = { + "operation": "Test Operation A", + "workstation": "_Test Workstation A", + "hour_rate_rent": 300, + "time_in_mins": 60 + } + make_workstation(row) + make_operation(row) + + bom_doc.append("operations", { + "operation": "Test Operation A", + "description": "Test Operation A", + "workstation": "_Test Workstation A", + "hour_rate": 300, + "time_in_mins": 60, + "operating_cost": 100 + }) + + bom_doc.transfer_material_against = "Job Card" + bom_doc.save() + bom_doc.submit() + + return bom_doc + +def make_wo_with_transfer_against_jc(): + "Create a WO with multiple operations and Material Transfer against Job Card" + + work_order = make_wo_order_test_record( + item="_Test FG Item 2", + qty=4, + transfer_material_against="Job Card", + source_warehouse="Stores - _TC", + do_not_submit=True + ) + work_order.required_items[0].operation = "Test Operation A" + work_order.required_items[1].operation = "_Test Operation 1" + work_order.submit() + + return work_order + +def make_bom_for_jc_tests(): + test_records = frappe.get_test_records('BOM') + bom = frappe.copy_doc(test_records[2]) + bom.set_rate_of_sub_assembly_item_based_on_bom = 0 + bom.rm_cost_as_per = "Valuation Rate" + bom.items[0].uom = "_Test UOM 1" + bom.items[0].conversion_factor = 5 + bom.insert() \ No newline at end of file diff --git a/erpnext/manufacturing/doctype/job_card_item/job_card_item.py b/erpnext/manufacturing/doctype/job_card_item/job_card_item.py index a1338364aa4..51a7b41f0d9 100644 --- a/erpnext/manufacturing/doctype/job_card_item/job_card_item.py +++ b/erpnext/manufacturing/doctype/job_card_item/job_card_item.py @@ -1,8 +1,6 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2018, Frappe Technologies Pvt. Ltd. and contributors # For license information, please see license.txt -from __future__ import unicode_literals from frappe.model.document import Document diff --git a/erpnext/manufacturing/doctype/job_card_operation/job_card_operation.py b/erpnext/manufacturing/doctype/job_card_operation/job_card_operation.py index 43d14220649..de44071c6ad 100644 --- a/erpnext/manufacturing/doctype/job_card_operation/job_card_operation.py +++ b/erpnext/manufacturing/doctype/job_card_operation/job_card_operation.py @@ -1,8 +1,6 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2020, Frappe Technologies Pvt. Ltd. and contributors # For license information, please see license.txt -from __future__ import unicode_literals # import frappe from frappe.model.document import Document diff --git a/erpnext/healthcare/doctype/dosage_strength/__init__.py b/erpnext/manufacturing/doctype/job_card_scrap_item/__init__.py similarity index 100% rename from erpnext/healthcare/doctype/dosage_strength/__init__.py rename to erpnext/manufacturing/doctype/job_card_scrap_item/__init__.py diff --git a/erpnext/manufacturing/doctype/job_card_scrap_item/job_card_scrap_item.json b/erpnext/manufacturing/doctype/job_card_scrap_item/job_card_scrap_item.json new file mode 100644 index 00000000000..9e9f1c4c89f --- /dev/null +++ b/erpnext/manufacturing/doctype/job_card_scrap_item/job_card_scrap_item.json @@ -0,0 +1,82 @@ +{ + "actions": [], + "creation": "2021-09-14 00:30:28.533884", + "doctype": "DocType", + "editable_grid": 1, + "engine": "InnoDB", + "field_order": [ + "item_code", + "item_name", + "column_break_3", + "description", + "quantity_and_rate", + "stock_qty", + "column_break_6", + "stock_uom" + ], + "fields": [ + { + "fieldname": "item_code", + "fieldtype": "Link", + "in_list_view": 1, + "label": "Scrap Item Code", + "options": "Item", + "reqd": 1 + }, + { + "fetch_from": "item_code.item_name", + "fieldname": "item_name", + "fieldtype": "Data", + "in_list_view": 1, + "label": "Scrap Item Name" + }, + { + "fieldname": "column_break_3", + "fieldtype": "Column Break" + }, + { + "fetch_from": "item_code.description", + "fieldname": "description", + "fieldtype": "Small Text", + "label": "Description", + "read_only": 1 + }, + { + "fieldname": "quantity_and_rate", + "fieldtype": "Section Break", + "label": "Quantity and Rate" + }, + { + "fieldname": "stock_qty", + "fieldtype": "Float", + "in_list_view": 1, + "label": "Qty", + "reqd": 1 + }, + { + "fieldname": "column_break_6", + "fieldtype": "Column Break" + }, + { + "fetch_from": "item_code.stock_uom", + "fieldname": "stock_uom", + "fieldtype": "Link", + "label": "Stock UOM", + "options": "UOM", + "read_only": 1 + } + ], + "index_web_pages_for_search": 1, + "istable": 1, + "links": [], + "modified": "2021-09-14 01:20:48.588052", + "modified_by": "Administrator", + "module": "Manufacturing", + "name": "Job Card Scrap Item", + "owner": "Administrator", + "permissions": [], + "quick_entry": 1, + "sort_field": "modified", + "sort_order": "DESC", + "track_changes": 1 +} \ No newline at end of file diff --git a/erpnext/manufacturing/doctype/job_card_scrap_item/job_card_scrap_item.py b/erpnext/manufacturing/doctype/job_card_scrap_item/job_card_scrap_item.py new file mode 100644 index 00000000000..372df1b0fad --- /dev/null +++ b/erpnext/manufacturing/doctype/job_card_scrap_item/job_card_scrap_item.py @@ -0,0 +1,8 @@ +# Copyright (c) 2021, Frappe Technologies Pvt. Ltd. and contributors +# For license information, please see license.txt + +from frappe.model.document import Document + + +class JobCardScrapItem(Document): + pass diff --git a/erpnext/manufacturing/doctype/job_card_time_log/job_card_time_log.py b/erpnext/manufacturing/doctype/job_card_time_log/job_card_time_log.py index ed27e7ff824..2b3ead383a3 100644 --- a/erpnext/manufacturing/doctype/job_card_time_log/job_card_time_log.py +++ b/erpnext/manufacturing/doctype/job_card_time_log/job_card_time_log.py @@ -1,8 +1,6 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2019, Frappe Technologies Pvt. Ltd. and contributors # For license information, please see license.txt -from __future__ import unicode_literals from frappe.model.document import Document diff --git a/erpnext/manufacturing/doctype/manufacturing_settings/manufacturing_settings.json b/erpnext/manufacturing/doctype/manufacturing_settings/manufacturing_settings.json index 024f7847259..01647d56c91 100644 --- a/erpnext/manufacturing/doctype/manufacturing_settings/manufacturing_settings.json +++ b/erpnext/manufacturing/doctype/manufacturing_settings/manufacturing_settings.json @@ -25,9 +25,12 @@ "overproduction_percentage_for_sales_order", "column_break_16", "overproduction_percentage_for_work_order", + "job_card_section", + "add_corrective_operation_cost_in_finished_good_valuation", + "column_break_24", + "job_card_excess_transfer", "other_settings_section", "update_bom_costs_automatically", - "add_corrective_operation_cost_in_finished_good_valuation", "column_break_23", "make_serial_no_batch_from_work_order" ], @@ -96,10 +99,10 @@ }, { "default": "0", - "description": "Allow multiple material consumptions against a Work Order", + "description": "Allow material consumptions without immediately manufacturing finished goods against a Work Order", "fieldname": "material_consumption", "fieldtype": "Check", - "label": "Allow Multiple Material Consumption" + "label": "Allow Continuous Material Consumption" }, { "default": "0", @@ -175,13 +178,29 @@ "fieldname": "add_corrective_operation_cost_in_finished_good_valuation", "fieldtype": "Check", "label": "Add Corrective Operation Cost in Finished Good Valuation" + }, + { + "fieldname": "job_card_section", + "fieldtype": "Section Break", + "label": "Job Card" + }, + { + "fieldname": "column_break_24", + "fieldtype": "Column Break" + }, + { + "default": "0", + "description": "Allow transferring raw materials even after the Required Quantity is fulfilled", + "fieldname": "job_card_excess_transfer", + "fieldtype": "Check", + "label": "Allow Excess Material Transfer" } ], "icon": "icon-wrench", "index_web_pages_for_search": 1, "issingle": 1, "links": [], - "modified": "2021-03-16 15:54:38.967341", + "modified": "2021-09-13 22:09:09.401559", "modified_by": "Administrator", "module": "Manufacturing", "name": "Manufacturing Settings", diff --git a/erpnext/manufacturing/doctype/manufacturing_settings/manufacturing_settings.py b/erpnext/manufacturing/doctype/manufacturing_settings/manufacturing_settings.py index 18d78b59f53..c919e8bef1d 100644 --- a/erpnext/manufacturing/doctype/manufacturing_settings/manufacturing_settings.py +++ b/erpnext/manufacturing/doctype/manufacturing_settings/manufacturing_settings.py @@ -1,7 +1,6 @@ # Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors and contributors # For license information, please see license.txt -from __future__ import unicode_literals import frappe from dateutil.relativedelta import relativedelta diff --git a/erpnext/manufacturing/doctype/manufacturing_settings/test_manufacturing_settings.py b/erpnext/manufacturing/doctype/manufacturing_settings/test_manufacturing_settings.py index fd0ac725914..1b2f18fc7ba 100644 --- a/erpnext/manufacturing/doctype/manufacturing_settings/test_manufacturing_settings.py +++ b/erpnext/manufacturing/doctype/manufacturing_settings/test_manufacturing_settings.py @@ -1,7 +1,5 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2018, Frappe Technologies Pvt. Ltd. and Contributors # See license.txt -from __future__ import unicode_literals import unittest diff --git a/erpnext/manufacturing/doctype/material_request_plan_item/material_request_plan_item.py b/erpnext/manufacturing/doctype/material_request_plan_item/material_request_plan_item.py index bc26644067f..3d5a7ce3fe0 100644 --- a/erpnext/manufacturing/doctype/material_request_plan_item/material_request_plan_item.py +++ b/erpnext/manufacturing/doctype/material_request_plan_item/material_request_plan_item.py @@ -1,8 +1,6 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2017, Frappe Technologies Pvt. Ltd. and contributors # For license information, please see license.txt -from __future__ import unicode_literals from frappe.model.document import Document diff --git a/erpnext/manufacturing/doctype/material_request_plan_item/test_material_request_plan_item.py b/erpnext/manufacturing/doctype/material_request_plan_item/test_material_request_plan_item.py index 2675af94a72..0654c1ebbbc 100644 --- a/erpnext/manufacturing/doctype/material_request_plan_item/test_material_request_plan_item.py +++ b/erpnext/manufacturing/doctype/material_request_plan_item/test_material_request_plan_item.py @@ -1,7 +1,5 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2017, Frappe Technologies Pvt. Ltd. and Contributors # See license.txt -from __future__ import unicode_literals import unittest diff --git a/erpnext/manufacturing/doctype/operation/operation.py b/erpnext/manufacturing/doctype/operation/operation.py index 2926f911ea1..41726f30cf5 100644 --- a/erpnext/manufacturing/doctype/operation/operation.py +++ b/erpnext/manufacturing/doctype/operation/operation.py @@ -1,7 +1,6 @@ # Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors and contributors # For license information, please see license.txt -from __future__ import unicode_literals import frappe from frappe import _ diff --git a/erpnext/manufacturing/doctype/operation/operation_dashboard.py b/erpnext/manufacturing/doctype/operation/operation_dashboard.py index 284fd9dfc2f..4fbcf4954ec 100644 --- a/erpnext/manufacturing/doctype/operation/operation_dashboard.py +++ b/erpnext/manufacturing/doctype/operation/operation_dashboard.py @@ -1,5 +1,3 @@ -from __future__ import unicode_literals - from frappe import _ diff --git a/erpnext/manufacturing/doctype/operation/test_operation.py b/erpnext/manufacturing/doctype/operation/test_operation.py index 2b24118fc41..e511084e7d0 100644 --- a/erpnext/manufacturing/doctype/operation/test_operation.py +++ b/erpnext/manufacturing/doctype/operation/test_operation.py @@ -1,6 +1,5 @@ # Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors # See license.txt -from __future__ import unicode_literals import unittest @@ -18,15 +17,13 @@ def make_operation(*args, **kwargs): args = frappe._dict(args) - try: + if not frappe.db.exists("Operation", args.operation): doc = frappe.get_doc({ "doctype": "Operation", "name": args.operation, "workstation": args.workstation }) - doc.insert() - return doc - except frappe.DuplicateEntryError: - return frappe.get_doc("Operation", args.operation) + + return frappe.get_doc("Operation", args.operation) diff --git a/erpnext/manufacturing/doctype/production_plan/production_plan.js b/erpnext/manufacturing/doctype/production_plan/production_plan.js index 7b4b7c3ca38..b171086b7ce 100644 --- a/erpnext/manufacturing/doctype/production_plan/production_plan.js +++ b/erpnext/manufacturing/doctype/production_plan/production_plan.js @@ -105,7 +105,7 @@ frappe.ui.form.on('Production Plan', { } frm.trigger("material_requirement"); - const projected_qty_formula = ` + const projected_qty_formula = `

@@ -242,6 +242,8 @@ frappe.ui.form.on('Production Plan', { }, get_sub_assembly_items: function(frm) { + frm.dirty(); + frappe.call({ method: "get_sub_assembly_items", freeze: true, @@ -434,6 +436,25 @@ frappe.ui.form.on("Material Request Plan Item", { } }); +frappe.ui.form.on("Production Plan Sales Order", { + sales_order(frm, cdt, cdn) { + const { sales_order } = locals[cdt][cdn]; + if (!sales_order) { + return; + } + frappe.call({ + method: "erpnext.manufacturing.doctype.production_plan.production_plan.get_so_details", + args: { sales_order }, + callback(r) { + const {transaction_date, customer, grand_total} = r.message; + frappe.model.set_value(cdt, cdn, 'sales_order_date', transaction_date); + frappe.model.set_value(cdt, cdn, 'customer', customer); + frappe.model.set_value(cdt, cdn, 'grand_total', grand_total); + } + }); + } +}); + cur_frm.fields_dict['sales_orders'].grid.get_field("sales_order").get_query = function() { return{ filters: [ diff --git a/erpnext/manufacturing/doctype/production_plan/production_plan.json b/erpnext/manufacturing/doctype/production_plan/production_plan.json index b5ed28802c8..56cf2b4f08a 100644 --- a/erpnext/manufacturing/doctype/production_plan/production_plan.json +++ b/erpnext/manufacturing/doctype/production_plan/production_plan.json @@ -16,10 +16,12 @@ "customer", "warehouse", "project", + "sales_order_status", "column_break2", "from_date", "to_date", - "sales_order_status", + "from_delivery_date", + "to_delivery_date", "sales_orders_detail", "get_sales_orders", "sales_orders", @@ -358,13 +360,23 @@ "fieldname": "get_sub_assembly_items", "fieldtype": "Button", "label": "Get Sub Assembly Items" + }, + { + "fieldname": "from_delivery_date", + "fieldtype": "Date", + "label": "From Delivery Date" + }, + { + "fieldname": "to_delivery_date", + "fieldtype": "Date", + "label": "To Delivery Date" } ], "icon": "fa fa-calendar", "index_web_pages_for_search": 1, "is_submittable": 1, "links": [], - "modified": "2021-08-23 17:26:03.799876", + "modified": "2021-09-06 18:35:59.642232", "modified_by": "Administrator", "module": "Manufacturing", "name": "Production Plan", diff --git a/erpnext/manufacturing/doctype/production_plan/production_plan.py b/erpnext/manufacturing/doctype/production_plan/production_plan.py index 91e57489644..7cec7f515a3 100644 --- a/erpnext/manufacturing/doctype/production_plan/production_plan.py +++ b/erpnext/manufacturing/doctype/production_plan/production_plan.py @@ -1,8 +1,6 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2017, Frappe Technologies Pvt. Ltd. and contributors # For license information, please see license.txt -from __future__ import unicode_literals import copy import json @@ -22,7 +20,6 @@ from frappe.utils import ( nowdate, ) from frappe.utils.csvutils import build_csv_response -from six import iteritems from erpnext.manufacturing.doctype.bom.bom import get_children, validate_bom_no from erpnext.manufacturing.doctype.work_order.work_order import get_item_details @@ -311,7 +308,7 @@ class ProductionPlan(Document): if self.total_produced_qty > 0: self.status = "In Process" - if self.total_produced_qty >= self.total_planned_qty: + if self.check_have_work_orders_completed(): self.status = "Completed" if self.status != 'Completed': @@ -424,7 +421,7 @@ class ProductionPlan(Document): po = frappe.new_doc('Purchase Order') po.supplier = supplier po.schedule_date = getdate(po_list[0].schedule_date) if po_list[0].schedule_date else nowdate() - po.is_subcontracted_item = 'Yes' + po.is_subcontracted = 'Yes' for row in po_list: args = { 'item_code': row.production_item, @@ -457,7 +454,8 @@ class ProductionPlan(Document): def prepare_args_for_sub_assembly_items(self, row, args): for field in ["production_item", "item_name", "qty", "fg_warehouse", - "description", "bom_no", "stock_uom", "bom_level", "production_plan_item"]: + "description", "bom_no", "stock_uom", "bom_level", + "production_plan_item", "schedule_date"]: args[field] = row.get(field) args.update({ @@ -561,8 +559,6 @@ class ProductionPlan(Document): get_sub_assembly_items(row.bom_no, bom_data, row.planned_qty) self.set_sub_assembly_items_based_on_level(row, bom_data, manufacturing_type) - self.save() - def set_sub_assembly_items_based_on_level(self, row, bom_data, manufacturing_type=None): bom_data = sorted(bom_data, key = lambda i: i.bom_level) @@ -576,6 +572,15 @@ class ProductionPlan(Document): self.append("sub_assembly_items", data) + def check_have_work_orders_completed(self): + wo_status = frappe.db.get_list( + "Work Order", + filters={"production_plan": self.name}, + fields="status", + pluck="status" + ) + return all(s == "Completed" for s in wo_status) + @frappe.whitelist() def download_raw_materials(doc, warehouses=None): if isinstance(doc, str): @@ -735,43 +740,42 @@ def get_material_request_items(row, sales_order, company, def get_sales_orders(self): so_filter = item_filter = "" bom_item = "bom.item = so_item.item_code" - if self.from_date: - so_filter += " and so.transaction_date >= %(from_date)s" - if self.to_date: - so_filter += " and so.transaction_date <= %(to_date)s" - if self.customer: - so_filter += " and so.customer = %(customer)s" - if self.project: - so_filter += " and so.project = %(project)s" - if self.sales_order_status: - so_filter += "and so.status = %(sales_order_status)s" + + date_field_mapper = { + 'from_date': ('>=', 'so.transaction_date'), + 'to_date': ('<=', 'so.transaction_date'), + 'from_delivery_date': ('>=', 'so_item.delivery_date'), + 'to_delivery_date': ('<=', 'so_item.delivery_date') + } + + for field, value in date_field_mapper.items(): + if self.get(field): + so_filter += f" and {value[1]} {value[0]} %({field})s" + + for field in ['customer', 'project', 'sales_order_status']: + if self.get(field): + so_field = 'status' if field == 'sales_order_status' else field + so_filter += f" and so.{so_field} = %({field})s" if self.item_code and frappe.db.exists('Item', self.item_code): bom_item = self.get_bom_item() or bom_item - item_filter += " and so_item.item_code = %(item)s" + item_filter += " and so_item.item_code = %(item_code)s" - open_so = frappe.db.sql(""" + open_so = frappe.db.sql(f""" select distinct so.name, so.transaction_date, so.customer, so.base_grand_total from `tabSales Order` so, `tabSales Order Item` so_item where so_item.parent = so.name and so.docstatus = 1 and so.status not in ("Stopped", "Closed") and so.company = %(company)s - and so_item.qty > so_item.work_order_qty {0} {1} - and (exists (select name from `tabBOM` bom where {2} + and so_item.qty > so_item.work_order_qty {so_filter} {item_filter} + and (exists (select name from `tabBOM` bom where {bom_item} and bom.is_active = 1) or exists (select name from `tabPacked Item` pi where pi.parent = so.name and pi.parent_item = so_item.item_code and exists (select name from `tabBOM` bom where bom.item=pi.item_code and bom.is_active = 1))) - """.format(so_filter, item_filter, bom_item), { - "from_date": self.from_date, - "to_date": self.to_date, - "customer": self.customer, - "project": self.project, - "item": self.item_code, - "company": self.company, - "sales_order_status": self.sales_order_status - }, as_dict=1) + """, self.as_dict(), as_dict=1) + return open_so @frappe.whitelist() @@ -800,6 +804,12 @@ def get_bin_details(row, company, for_warehouse=None, all_warehouse=False): group by item_code, warehouse """.format(conditions=conditions), { "item_code": row['item_code'] }, as_dict=1) +@frappe.whitelist() +def get_so_details(sales_order): + return frappe.db.get_value("Sales Order", sales_order, + ['transaction_date', 'customer', 'grand_total'], as_dict=1 + ) + def get_warehouse_list(warehouses): warehouse_list = [] @@ -895,7 +905,7 @@ def get_items_for_material_requests(doc, warehouses=None, get_parent_warehouse_d sales_order = doc.get("sales_order") - for item_code, details in iteritems(item_details): + for item_code, details in item_details.items(): so_item_details.setdefault(sales_order, frappe._dict()) if item_code in so_item_details.get(sales_order, {}): so_item_details[sales_order][item_code]['qty'] = so_item_details[sales_order][item_code].get("qty", 0) + flt(details.qty) @@ -903,7 +913,7 @@ def get_items_for_material_requests(doc, warehouses=None, get_parent_warehouse_d so_item_details[sales_order][item_code] = details mr_items = [] - for sales_order, item_code in iteritems(so_item_details): + for sales_order, item_code in so_item_details.items(): item_dict = so_item_details[sales_order] for details in item_dict.values(): bin_dict = get_bin_details(details, doc.company, warehouse) diff --git a/erpnext/manufacturing/doctype/production_plan/production_plan_dashboard.py b/erpnext/manufacturing/doctype/production_plan/production_plan_dashboard.py index b4bc3467e46..e13f042e435 100644 --- a/erpnext/manufacturing/doctype/production_plan/production_plan_dashboard.py +++ b/erpnext/manufacturing/doctype/production_plan/production_plan_dashboard.py @@ -1,5 +1,3 @@ -from __future__ import unicode_literals - from frappe import _ diff --git a/erpnext/manufacturing/doctype/production_plan/test_production_plan.py b/erpnext/manufacturing/doctype/production_plan/test_production_plan.py index 6a942d54335..a2980a732ed 100644 --- a/erpnext/manufacturing/doctype/production_plan/test_production_plan.py +++ b/erpnext/manufacturing/doctype/production_plan/test_production_plan.py @@ -1,7 +1,5 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2017, Frappe Technologies Pvt. Ltd. and Contributors # See license.txt -from __future__ import unicode_literals import unittest @@ -404,6 +402,7 @@ def make_bom(**args): 'uom': item_doc.stock_uom, 'stock_uom': item_doc.stock_uom, 'rate': item_doc.valuation_rate or args.rate, + 'source_warehouse': args.source_warehouse }) if not args.do_not_save: diff --git a/erpnext/manufacturing/doctype/production_plan_item/__init__.py b/erpnext/manufacturing/doctype/production_plan_item/__init__.py index baffc488252..e69de29bb2d 100644 --- a/erpnext/manufacturing/doctype/production_plan_item/__init__.py +++ b/erpnext/manufacturing/doctype/production_plan_item/__init__.py @@ -1 +0,0 @@ -from __future__ import unicode_literals diff --git a/erpnext/manufacturing/doctype/production_plan_item/production_plan_item.py b/erpnext/manufacturing/doctype/production_plan_item/production_plan_item.py index 24029d8f2ce..cc79ac327db 100644 --- a/erpnext/manufacturing/doctype/production_plan_item/production_plan_item.py +++ b/erpnext/manufacturing/doctype/production_plan_item/production_plan_item.py @@ -1,7 +1,6 @@ # Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors # License: GNU General Public License v3. See license.txt -from __future__ import unicode_literals from frappe.model.document import Document diff --git a/erpnext/manufacturing/doctype/production_plan_item_reference/production_plan_item_reference.py b/erpnext/manufacturing/doctype/production_plan_item_reference/production_plan_item_reference.py index 9d25d6fc20f..81d2ecad544 100644 --- a/erpnext/manufacturing/doctype/production_plan_item_reference/production_plan_item_reference.py +++ b/erpnext/manufacturing/doctype/production_plan_item_reference/production_plan_item_reference.py @@ -1,8 +1,6 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2021, Frappe Technologies Pvt. Ltd. and contributors # For license information, please see license.txt -from __future__ import unicode_literals # import frappe from frappe.model.document import Document diff --git a/erpnext/manufacturing/doctype/production_plan_material_request/production_plan_material_request.py b/erpnext/manufacturing/doctype/production_plan_material_request/production_plan_material_request.py index d1d935c955b..83b17893c04 100644 --- a/erpnext/manufacturing/doctype/production_plan_material_request/production_plan_material_request.py +++ b/erpnext/manufacturing/doctype/production_plan_material_request/production_plan_material_request.py @@ -1,8 +1,6 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and contributors # For license information, please see license.txt -from __future__ import unicode_literals from frappe.model.document import Document diff --git a/erpnext/manufacturing/doctype/production_plan_material_request_warehouse/production_plan_material_request_warehouse.py b/erpnext/manufacturing/doctype/production_plan_material_request_warehouse/production_plan_material_request_warehouse.py index 1548bd7b88a..a66ff44f558 100644 --- a/erpnext/manufacturing/doctype/production_plan_material_request_warehouse/production_plan_material_request_warehouse.py +++ b/erpnext/manufacturing/doctype/production_plan_material_request_warehouse/production_plan_material_request_warehouse.py @@ -1,8 +1,6 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2020, Frappe Technologies Pvt. Ltd. and contributors # For license information, please see license.txt -from __future__ import unicode_literals # import frappe from frappe.model.document import Document diff --git a/erpnext/manufacturing/doctype/production_plan_material_request_warehouse/test_production_plan_material_request_warehouse.py b/erpnext/manufacturing/doctype/production_plan_material_request_warehouse/test_production_plan_material_request_warehouse.py index 905252da604..4394c142d49 100644 --- a/erpnext/manufacturing/doctype/production_plan_material_request_warehouse/test_production_plan_material_request_warehouse.py +++ b/erpnext/manufacturing/doctype/production_plan_material_request_warehouse/test_production_plan_material_request_warehouse.py @@ -1,7 +1,5 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2020, Frappe Technologies Pvt. Ltd. and Contributors # See license.txt -from __future__ import unicode_literals # import frappe import unittest diff --git a/erpnext/manufacturing/doctype/production_plan_sales_order/__init__.py b/erpnext/manufacturing/doctype/production_plan_sales_order/__init__.py index baffc488252..e69de29bb2d 100644 --- a/erpnext/manufacturing/doctype/production_plan_sales_order/__init__.py +++ b/erpnext/manufacturing/doctype/production_plan_sales_order/__init__.py @@ -1 +0,0 @@ -from __future__ import unicode_literals diff --git a/erpnext/manufacturing/doctype/production_plan_sales_order/production_plan_sales_order.py b/erpnext/manufacturing/doctype/production_plan_sales_order/production_plan_sales_order.py index ea53a986964..3f3852983ce 100644 --- a/erpnext/manufacturing/doctype/production_plan_sales_order/production_plan_sales_order.py +++ b/erpnext/manufacturing/doctype/production_plan_sales_order/production_plan_sales_order.py @@ -1,7 +1,6 @@ # Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors # License: GNU General Public License v3. See license.txt -from __future__ import unicode_literals from frappe.model.document import Document diff --git a/erpnext/manufacturing/doctype/production_plan_sub_assembly_item/production_plan_sub_assembly_item.py b/erpnext/manufacturing/doctype/production_plan_sub_assembly_item/production_plan_sub_assembly_item.py index be0ed1b96a8..069667a6410 100644 --- a/erpnext/manufacturing/doctype/production_plan_sub_assembly_item/production_plan_sub_assembly_item.py +++ b/erpnext/manufacturing/doctype/production_plan_sub_assembly_item/production_plan_sub_assembly_item.py @@ -1,8 +1,6 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2020, Frappe Technologies Pvt. Ltd. and contributors # For license information, please see license.txt -from __future__ import unicode_literals # import frappe from frappe.model.document import Document diff --git a/erpnext/manufacturing/doctype/routing/routing.py b/erpnext/manufacturing/doctype/routing/routing.py index 20fb370d942..1c76634646d 100644 --- a/erpnext/manufacturing/doctype/routing/routing.py +++ b/erpnext/manufacturing/doctype/routing/routing.py @@ -1,8 +1,6 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2018, Frappe Technologies Pvt. Ltd. and contributors # For license information, please see license.txt -from __future__ import unicode_literals import frappe from frappe import _ diff --git a/erpnext/manufacturing/doctype/routing/routing_dashboard.py b/erpnext/manufacturing/doctype/routing/routing_dashboard.py index 9ef6ee57523..d051e38a34c 100644 --- a/erpnext/manufacturing/doctype/routing/routing_dashboard.py +++ b/erpnext/manufacturing/doctype/routing/routing_dashboard.py @@ -1,6 +1,3 @@ -from __future__ import unicode_literals - - def get_data(): return { 'fieldname': 'routing', diff --git a/erpnext/manufacturing/doctype/routing/test_routing.py b/erpnext/manufacturing/doctype/routing/test_routing.py index b84b2ba1e6d..68d9dec04b1 100644 --- a/erpnext/manufacturing/doctype/routing/test_routing.py +++ b/erpnext/manufacturing/doctype/routing/test_routing.py @@ -1,7 +1,5 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2018, Frappe Technologies Pvt. Ltd. and Contributors # See license.txt -from __future__ import unicode_literals import unittest diff --git a/erpnext/manufacturing/doctype/sub_operation/sub_operation.py b/erpnext/manufacturing/doctype/sub_operation/sub_operation.py index 37b64f23d29..c86058eb586 100644 --- a/erpnext/manufacturing/doctype/sub_operation/sub_operation.py +++ b/erpnext/manufacturing/doctype/sub_operation/sub_operation.py @@ -1,8 +1,6 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2020, Frappe Technologies Pvt. Ltd. and contributors # For license information, please see license.txt -from __future__ import unicode_literals # import frappe from frappe.model.document import Document diff --git a/erpnext/manufacturing/doctype/sub_operation/test_sub_operation.py b/erpnext/manufacturing/doctype/sub_operation/test_sub_operation.py index c5749dbc962..189fdaee085 100644 --- a/erpnext/manufacturing/doctype/sub_operation/test_sub_operation.py +++ b/erpnext/manufacturing/doctype/sub_operation/test_sub_operation.py @@ -1,7 +1,5 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2020, Frappe Technologies Pvt. Ltd. and Contributors # See license.txt -from __future__ import unicode_literals # import frappe import unittest diff --git a/erpnext/manufacturing/doctype/work_order/__init__.py b/erpnext/manufacturing/doctype/work_order/__init__.py index baffc488252..e69de29bb2d 100644 --- a/erpnext/manufacturing/doctype/work_order/__init__.py +++ b/erpnext/manufacturing/doctype/work_order/__init__.py @@ -1 +0,0 @@ -from __future__ import unicode_literals diff --git a/erpnext/manufacturing/doctype/work_order/test_work_order.py b/erpnext/manufacturing/doctype/work_order/test_work_order.py index bb431498636..f4a88dc4598 100644 --- a/erpnext/manufacturing/doctype/work_order/test_work_order.py +++ b/erpnext/manufacturing/doctype/work_order/test_work_order.py @@ -1,9 +1,5 @@ -# Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors +# Copyright (c) 2021, Frappe Technologies Pvt. Ltd. and Contributors # License: GNU General Public License v3. See license.txt - - -from __future__ import unicode_literals - import unittest import frappe @@ -16,11 +12,12 @@ from erpnext.manufacturing.doctype.work_order.work_order import ( ItemHasVariantError, OverProductionError, StockOverProductionError, + close_work_order, make_stock_entry, stop_unstop, ) from erpnext.selling.doctype.sales_order.test_sales_order import make_sales_order -from erpnext.stock.doctype.item.test_item import make_item +from erpnext.stock.doctype.item.test_item import create_item, make_item from erpnext.stock.doctype.stock_entry import test_stock_entry from erpnext.stock.doctype.warehouse.test_warehouse import create_warehouse from erpnext.stock.utils import get_bin @@ -772,6 +769,100 @@ class TestWorkOrder(unittest.TestCase): total_pl_qty ) + def test_job_card_scrap_item(self): + items = ['Test FG Item for Scrap Item Test', 'Test RM Item 1 for Scrap Item Test', + 'Test RM Item 2 for Scrap Item Test'] + + company = '_Test Company with perpetual inventory' + for item_code in items: + create_item(item_code = item_code, is_stock_item = 1, + is_purchase_item=1, opening_stock=100, valuation_rate=10, company=company, warehouse='Stores - TCP1') + + item = 'Test FG Item for Scrap Item Test' + raw_materials = ['Test RM Item 1 for Scrap Item Test', 'Test RM Item 2 for Scrap Item Test'] + if not frappe.db.get_value('BOM', {'item': item}): + bom = make_bom(item=item, source_warehouse='Stores - TCP1', raw_materials=raw_materials, do_not_save=True) + bom.with_operations = 1 + bom.append('operations', { + 'operation': '_Test Operation 1', + 'workstation': '_Test Workstation 1', + 'hour_rate': 20, + 'time_in_mins': 60 + }) + + bom.submit() + + wo_order = make_wo_order_test_record(item=item, company=company, planned_start_date=now(), qty=20, skip_transfer=1) + job_card = frappe.db.get_value('Job Card', {'work_order': wo_order.name}, 'name') + update_job_card(job_card) + + stock_entry = frappe.get_doc(make_stock_entry(wo_order.name, "Manufacture", 10)) + for row in stock_entry.items: + if row.is_scrap_item: + self.assertEqual(row.qty, 1) + + def test_close_work_order(self): + items = ['Test FG Item for Closed WO', 'Test RM Item 1 for Closed WO', + 'Test RM Item 2 for Closed WO'] + + company = '_Test Company with perpetual inventory' + for item_code in items: + create_item(item_code = item_code, is_stock_item = 1, + is_purchase_item=1, opening_stock=100, valuation_rate=10, company=company, warehouse='Stores - TCP1') + + item = 'Test FG Item for Closed WO' + raw_materials = ['Test RM Item 1 for Closed WO', 'Test RM Item 2 for Closed WO'] + if not frappe.db.get_value('BOM', {'item': item}): + bom = make_bom(item=item, source_warehouse='Stores - TCP1', raw_materials=raw_materials, do_not_save=True) + bom.with_operations = 1 + bom.append('operations', { + 'operation': '_Test Operation 1', + 'workstation': '_Test Workstation 1', + 'hour_rate': 20, + 'time_in_mins': 60 + }) + + bom.submit() + + wo_order = make_wo_order_test_record(item=item, company=company, planned_start_date=now(), qty=20, skip_transfer=1) + job_cards = frappe.db.get_value('Job Card', {'work_order': wo_order.name}, 'name') + + if len(job_cards) == len(bom.operations): + for jc in job_cards: + job_card_doc = frappe.get_doc('Job Card', jc) + job_card_doc.append('time_logs', { + 'from_time': now(), + 'time_in_mins': 60, + 'completed_qty': job_card_doc.for_quantity + }) + + job_card_doc.submit() + + close_work_order(wo_order, "Closed") + self.assertEqual(wo_order.get('status'), "Closed") + +def update_job_card(job_card): + job_card_doc = frappe.get_doc('Job Card', job_card) + job_card_doc.set('scrap_items', [ + { + 'item_code': 'Test RM Item 1 for Scrap Item Test', + 'stock_qty': 2 + }, + { + 'item_code': 'Test RM Item 2 for Scrap Item Test', + 'stock_qty': 2 + }, + ]) + + job_card_doc.append('time_logs', { + 'from_time': now(), + 'time_in_mins': 60, + 'completed_qty': job_card_doc.for_quantity + }) + + job_card_doc.submit() + + def get_scrap_item_details(bom_no): scrap_items = {} for item in frappe.db.sql("""select item_code, stock_qty from `tabBOM Scrap Item` @@ -814,6 +905,7 @@ def make_wo_order_test_record(**args): wo_order.get_items_and_operations_from_bom() wo_order.sales_order = args.sales_order or None wo_order.planned_start_date = args.planned_start_date or now() + wo_order.transfer_material_against = args.transfer_material_against or "Work Order" if args.source_warehouse: for item in wo_order.get("required_items"): diff --git a/erpnext/manufacturing/doctype/work_order/work_order.js b/erpnext/manufacturing/doctype/work_order/work_order.js index 51c46f63ab7..bfce1b8cbec 100644 --- a/erpnext/manufacturing/doctype/work_order/work_order.js +++ b/erpnext/manufacturing/doctype/work_order/work_order.js @@ -135,24 +135,26 @@ frappe.ui.form.on("Work Order", { frm.set_intro(__("Submit this Work Order for further processing.")); } - if (frm.doc.docstatus===1) { - frm.trigger('show_progress_for_items'); - frm.trigger('show_progress_for_operations'); - } + if (frm.doc.status != "Closed") { + if (frm.doc.docstatus===1) { + frm.trigger('show_progress_for_items'); + frm.trigger('show_progress_for_operations'); + } - if (frm.doc.docstatus === 1 - && frm.doc.operations && frm.doc.operations.length) { + if (frm.doc.docstatus === 1 + && frm.doc.operations && frm.doc.operations.length) { - const not_completed = frm.doc.operations.filter(d => { - if(d.status != 'Completed') { - return true; + const not_completed = frm.doc.operations.filter(d => { + if (d.status != 'Completed') { + return true; + } + }); + + if (not_completed && not_completed.length) { + frm.add_custom_button(__('Create Job Card'), () => { + frm.trigger("make_job_card"); + }).addClass('btn-primary'); } - }); - - if(not_completed && not_completed.length) { - frm.add_custom_button(__('Create Job Card'), () => { - frm.trigger("make_job_card"); - }).addClass('btn-primary'); } } @@ -517,14 +519,22 @@ frappe.ui.form.on("Work Order Operation", { erpnext.work_order = { set_custom_buttons: function(frm) { var doc = frm.doc; - if (doc.docstatus === 1) { + if (doc.docstatus === 1 && doc.status != "Closed") { + frm.add_custom_button(__('Close'), function() { + frappe.confirm(__("Once the Work Order is Closed. It can't be resumed."), + () => { + erpnext.work_order.change_work_order_status(frm, "Closed"); + } + ); + }, __("Status")); + if (doc.status != 'Stopped' && doc.status != 'Completed') { frm.add_custom_button(__('Stop'), function() { - erpnext.work_order.stop_work_order(frm, "Stopped"); + erpnext.work_order.change_work_order_status(frm, "Stopped"); }, __("Status")); } else if (doc.status == 'Stopped') { frm.add_custom_button(__('Re-open'), function() { - erpnext.work_order.stop_work_order(frm, "Resumed"); + erpnext.work_order.change_work_order_status(frm, "Resumed"); }, __("Status")); } @@ -713,9 +723,10 @@ erpnext.work_order = { }); }, - stop_work_order: function(frm, status) { + change_work_order_status: function(frm, status) { + let method_name = status=="Closed" ? "close_work_order" : "stop_unstop"; frappe.call({ - method: "erpnext.manufacturing.doctype.work_order.work_order.stop_unstop", + method: `erpnext.manufacturing.doctype.work_order.work_order.${method_name}`, freeze: true, freeze_message: __("Updating Work Order status"), args: { diff --git a/erpnext/manufacturing/doctype/work_order/work_order.json b/erpnext/manufacturing/doctype/work_order/work_order.json index 913fc85af61..df7ee53b92d 100644 --- a/erpnext/manufacturing/doctype/work_order/work_order.json +++ b/erpnext/manufacturing/doctype/work_order/work_order.json @@ -99,7 +99,7 @@ "no_copy": 1, "oldfieldname": "status", "oldfieldtype": "Select", - "options": "\nDraft\nSubmitted\nNot Started\nIn Process\nCompleted\nStopped\nCancelled", + "options": "\nDraft\nSubmitted\nNot Started\nIn Process\nCompleted\nStopped\nClosed\nCancelled", "read_only": 1, "reqd": 1, "search_index": 1 @@ -182,6 +182,7 @@ "reqd": 1 }, { + "default": "1.0", "fieldname": "qty", "fieldtype": "Float", "label": "Qty To Manufacture", @@ -572,10 +573,12 @@ "image_field": "image", "is_submittable": 1, "links": [], - "modified": "2021-08-24 15:14:03.844937", + "migration_hash": "a18118963f4fcdb7f9d326de5f4063ba", + "modified": "2021-10-29 15:12:32.203605", "modified_by": "Administrator", "module": "Manufacturing", "name": "Work Order", + "naming_rule": "By \"Naming Series\" field", "nsm_parent_field": "parent_work_order", "owner": "Administrator", "permissions": [ diff --git a/erpnext/manufacturing/doctype/work_order/work_order.py b/erpnext/manufacturing/doctype/work_order/work_order.py index e282dd3ecba..0090f4d04ee 100644 --- a/erpnext/manufacturing/doctype/work_order/work_order.py +++ b/erpnext/manufacturing/doctype/work_order/work_order.py @@ -175,7 +175,7 @@ class WorkOrder(Document): def update_status(self, status=None): '''Update status of work order if unknown''' - if status != "Stopped": + if status != "Stopped" and status != "Closed": status = self.get_status(status) if status != self.status: @@ -624,7 +624,6 @@ class WorkOrder(Document): def validate_operation_time(self): for d in self.operations: if not d.time_in_mins > 0: - print(self.bom_no, self.production_item) frappe.throw(_("Operation Time must be greater than 0 for Operation {0}").format(d.operation)) def update_required_items(self): @@ -685,9 +684,7 @@ class WorkOrder(Document): if not d.operation: d.operation = operation else: - # Attribute a big number (999) to idx for sorting putpose in case idx is NULL - # For instance in BOM Explosion Item child table, the items coming from sub assembly items - for item in sorted(item_dict.values(), key=lambda d: d['idx'] or 9999): + for item in sorted(item_dict.values(), key=lambda d: d['idx'] or float('inf')): self.append('required_items', { 'rate': item.rate, 'amount': item.rate * item.qty, @@ -969,6 +966,10 @@ def stop_unstop(work_order, status): frappe.throw(_("Not permitted"), frappe.PermissionError) pro_order = frappe.get_doc("Work Order", work_order) + + if pro_order.status == "Closed": + frappe.throw(_("Closed Work Order can not be stopped or Re-opened")) + pro_order.update_status(status) pro_order.update_planned_qty() frappe.msgprint(_("Work Order has been {0}").format(status)) @@ -1003,6 +1004,29 @@ def make_job_card(work_order, operations): if row.job_card_qty > 0: create_job_card(work_order, row, auto_create=True) +@frappe.whitelist() +def close_work_order(work_order, status): + if not frappe.has_permission("Work Order", "write"): + frappe.throw(_("Not permitted"), frappe.PermissionError) + + work_order = frappe.get_doc("Work Order", work_order) + if work_order.get("operations"): + job_cards = frappe.get_list("Job Card", + filters={ + "work_order": work_order.name, + "status": "Work In Progress" + }, pluck='name') + + if job_cards: + job_cards = ", ".join(job_cards) + frappe.throw(_("Can not close Work Order. Since {0} Job Cards are in Work In Progress state.").format(job_cards)) + + work_order.update_status(status) + work_order.update_planned_qty() + frappe.msgprint(_("Work Order has been {0}").format(status)) + work_order.notify_update() + return work_order.status + def split_qty_based_on_batch_size(wo_doc, row, qty): if not cint(frappe.db.get_value("Operation", row.operation, "create_job_card_based_on_batch_size")): diff --git a/erpnext/manufacturing/doctype/work_order/work_order_dashboard.py b/erpnext/manufacturing/doctype/work_order/work_order_dashboard.py index f0fc43f1656..37dd11aab4f 100644 --- a/erpnext/manufacturing/doctype/work_order/work_order_dashboard.py +++ b/erpnext/manufacturing/doctype/work_order/work_order_dashboard.py @@ -1,5 +1,3 @@ -from __future__ import unicode_literals - from frappe import _ diff --git a/erpnext/manufacturing/doctype/work_order_item/work_order_item.py b/erpnext/manufacturing/doctype/work_order_item/work_order_item.py index 3f2664b16e9..4311d3bf17f 100644 --- a/erpnext/manufacturing/doctype/work_order_item/work_order_item.py +++ b/erpnext/manufacturing/doctype/work_order_item/work_order_item.py @@ -1,8 +1,6 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and contributors # For license information, please see license.txt -from __future__ import unicode_literals import frappe from frappe.model.document import Document diff --git a/erpnext/manufacturing/doctype/work_order_operation/work_order_operation.py b/erpnext/manufacturing/doctype/work_order_operation/work_order_operation.py index d25c9f21890..6bda58ea77e 100644 --- a/erpnext/manufacturing/doctype/work_order_operation/work_order_operation.py +++ b/erpnext/manufacturing/doctype/work_order_operation/work_order_operation.py @@ -1,7 +1,6 @@ # Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors and contributors # For license information, please see license.txt -from __future__ import unicode_literals from frappe.model.document import Document diff --git a/erpnext/manufacturing/doctype/workstation/__init__.py b/erpnext/manufacturing/doctype/workstation/__init__.py index baffc488252..e69de29bb2d 100644 --- a/erpnext/manufacturing/doctype/workstation/__init__.py +++ b/erpnext/manufacturing/doctype/workstation/__init__.py @@ -1 +0,0 @@ -from __future__ import unicode_literals diff --git a/erpnext/manufacturing/doctype/workstation/test_workstation.py b/erpnext/manufacturing/doctype/workstation/test_workstation.py index 6c6ab77dd8f..5ed51535282 100644 --- a/erpnext/manufacturing/doctype/workstation/test_workstation.py +++ b/erpnext/manufacturing/doctype/workstation/test_workstation.py @@ -1,6 +1,5 @@ # Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors and Contributors # See license.txt -from __future__ import unicode_literals import unittest @@ -90,7 +89,7 @@ def make_workstation(*args, **kwargs): args = frappe._dict(args) workstation_name = args.workstation_name or args.workstation - try: + if not frappe.db.exists("Workstation", workstation_name): doc = frappe.get_doc({ "doctype": "Workstation", "workstation_name": workstation_name @@ -100,5 +99,5 @@ def make_workstation(*args, **kwargs): doc.insert() return doc - except frappe.DuplicateEntryError: - return frappe.get_doc("Workstation", workstation_name) + + return frappe.get_doc("Workstation", workstation_name) diff --git a/erpnext/manufacturing/doctype/workstation/workstation.py b/erpnext/manufacturing/doctype/workstation/workstation.py index 6daf950c5ff..4cfd410ac72 100644 --- a/erpnext/manufacturing/doctype/workstation/workstation.py +++ b/erpnext/manufacturing/doctype/workstation/workstation.py @@ -1,7 +1,6 @@ # Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors # License: GNU General Public License v3. See license.txt -from __future__ import unicode_literals import frappe from frappe import _ diff --git a/erpnext/manufacturing/doctype/workstation/workstation_dashboard.py b/erpnext/manufacturing/doctype/workstation/workstation_dashboard.py index 3e4b38aae85..bc481ca1926 100644 --- a/erpnext/manufacturing/doctype/workstation/workstation_dashboard.py +++ b/erpnext/manufacturing/doctype/workstation/workstation_dashboard.py @@ -1,5 +1,3 @@ -from __future__ import unicode_literals - from frappe import _ diff --git a/erpnext/manufacturing/doctype/workstation_working_hour/workstation_working_hour.py b/erpnext/manufacturing/doctype/workstation_working_hour/workstation_working_hour.py index 719d83db51a..99fb5524a90 100644 --- a/erpnext/manufacturing/doctype/workstation_working_hour/workstation_working_hour.py +++ b/erpnext/manufacturing/doctype/workstation_working_hour/workstation_working_hour.py @@ -1,7 +1,6 @@ # Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors and contributors # For license information, please see license.txt -from __future__ import unicode_literals from frappe.model.document import Document diff --git a/erpnext/manufacturing/notification/material_request_receipt_notification/material_request_receipt_notification.py b/erpnext/manufacturing/notification/material_request_receipt_notification/material_request_receipt_notification.py index f57de916dd1..02e3e933330 100644 --- a/erpnext/manufacturing/notification/material_request_receipt_notification/material_request_receipt_notification.py +++ b/erpnext/manufacturing/notification/material_request_receipt_notification/material_request_receipt_notification.py @@ -1,6 +1,3 @@ -from __future__ import unicode_literals - - def get_context(context): # do your magic here pass diff --git a/erpnext/manufacturing/report/bom_explorer/bom_explorer.py b/erpnext/manufacturing/report/bom_explorer/bom_explorer.py index c122fa9b614..25de2e03797 100644 --- a/erpnext/manufacturing/report/bom_explorer/bom_explorer.py +++ b/erpnext/manufacturing/report/bom_explorer/bom_explorer.py @@ -1,7 +1,6 @@ # Copyright (c) 2013, Frappe Technologies Pvt. Ltd. and contributors # For license information, please see license.txt -from __future__ import unicode_literals import frappe diff --git a/erpnext/manufacturing/report/bom_operations_time/bom_operations_time.py b/erpnext/manufacturing/report/bom_operations_time/bom_operations_time.py index 3c2d2153697..e7a818abd5d 100644 --- a/erpnext/manufacturing/report/bom_operations_time/bom_operations_time.py +++ b/erpnext/manufacturing/report/bom_operations_time/bom_operations_time.py @@ -1,7 +1,6 @@ # Copyright (c) 2013, Frappe Technologies Pvt. Ltd. and contributors # For license information, please see license.txt -from __future__ import unicode_literals import frappe from frappe import _ diff --git a/erpnext/manufacturing/report/bom_stock_calculated/bom_stock_calculated.py b/erpnext/manufacturing/report/bom_stock_calculated/bom_stock_calculated.py index c085990acc3..cf19cbf6a28 100644 --- a/erpnext/manufacturing/report/bom_stock_calculated/bom_stock_calculated.py +++ b/erpnext/manufacturing/report/bom_stock_calculated/bom_stock_calculated.py @@ -1,7 +1,6 @@ # Copyright (c) 2013, Frappe Technologies Pvt. Ltd. and contributors # For license information, please see license.txt -from __future__ import unicode_literals import frappe from frappe import _ diff --git a/erpnext/manufacturing/report/bom_stock_report/bom_stock_report.py b/erpnext/manufacturing/report/bom_stock_report/bom_stock_report.py index b8ef68dbb68..fa943912617 100644 --- a/erpnext/manufacturing/report/bom_stock_report/bom_stock_report.py +++ b/erpnext/manufacturing/report/bom_stock_report/bom_stock_report.py @@ -1,7 +1,6 @@ # Copyright (c) 2013, Frappe Technologies Pvt. Ltd. and contributors # For license information, please see license.txt -from __future__ import unicode_literals import frappe from frappe import _ diff --git a/erpnext/manufacturing/report/bom_variance_report/bom_variance_report.py b/erpnext/manufacturing/report/bom_variance_report/bom_variance_report.py index bbf503718f9..a5ae43e9add 100644 --- a/erpnext/manufacturing/report/bom_variance_report/bom_variance_report.py +++ b/erpnext/manufacturing/report/bom_variance_report/bom_variance_report.py @@ -1,7 +1,6 @@ # Copyright (c) 2013, Frappe Technologies Pvt. Ltd. and contributors # For license information, please see license.txt -from __future__ import unicode_literals import frappe from frappe import _ diff --git a/erpnext/manufacturing/report/cost_of_poor_quality_report/cost_of_poor_quality_report.py b/erpnext/manufacturing/report/cost_of_poor_quality_report/cost_of_poor_quality_report.py index 0dcad448d79..b9ddc9f075f 100644 --- a/erpnext/manufacturing/report/cost_of_poor_quality_report/cost_of_poor_quality_report.py +++ b/erpnext/manufacturing/report/cost_of_poor_quality_report/cost_of_poor_quality_report.py @@ -1,7 +1,6 @@ # Copyright (c) 2013, Frappe Technologies Pvt. Ltd. and contributors # For license information, please see license.txt -from __future__ import unicode_literals import frappe from frappe import _ diff --git a/erpnext/manufacturing/report/downtime_analysis/downtime_analysis.py b/erpnext/manufacturing/report/downtime_analysis/downtime_analysis.py index a1c6fd12622..2c515d1b36f 100644 --- a/erpnext/manufacturing/report/downtime_analysis/downtime_analysis.py +++ b/erpnext/manufacturing/report/downtime_analysis/downtime_analysis.py @@ -1,7 +1,6 @@ # Copyright (c) 2013, Frappe Technologies Pvt. Ltd. and contributors # For license information, please see license.txt -from __future__ import unicode_literals import frappe from frappe import _ diff --git a/erpnext/manufacturing/report/exponential_smoothing_forecasting/exponential_smoothing_forecasting.py b/erpnext/manufacturing/report/exponential_smoothing_forecasting/exponential_smoothing_forecasting.py index f014e7f9b57..26b3359dee1 100644 --- a/erpnext/manufacturing/report/exponential_smoothing_forecasting/exponential_smoothing_forecasting.py +++ b/erpnext/manufacturing/report/exponential_smoothing_forecasting/exponential_smoothing_forecasting.py @@ -1,7 +1,6 @@ # Copyright (c) 2020, Frappe Technologies Pvt. Ltd. and contributors # For license information, please see license.txt -from __future__ import unicode_literals import frappe from frappe import _ diff --git a/erpnext/manufacturing/report/job_card_summary/job_card_summary.py b/erpnext/manufacturing/report/job_card_summary/job_card_summary.py index a7aec315ff2..4046bb12b86 100644 --- a/erpnext/manufacturing/report/job_card_summary/job_card_summary.py +++ b/erpnext/manufacturing/report/job_card_summary/job_card_summary.py @@ -1,7 +1,6 @@ # Copyright (c) 2013, Frappe Technologies Pvt. Ltd. and contributors # For license information, please see license.txt -from __future__ import unicode_literals import frappe from frappe import _ @@ -24,7 +23,7 @@ def get_data(filters): } fields = ["name", "status", "work_order", "production_item", "item_name", "posting_date", - "total_completed_qty", "workstation", "operation", "employee_name", "total_time_in_mins"] + "total_completed_qty", "workstation", "operation", "total_time_in_mins"] for field in ["work_order", "workstation", "operation", "company"]: if filters.get(field): @@ -45,7 +44,7 @@ def get_data(filters): job_card_time_details = {} for job_card_data in frappe.get_all("Job Card Time Log", fields=["min(from_time) as from_time", "max(to_time) as to_time", "parent"], - filters=job_card_time_filter, group_by="parent", debug=1): + filters=job_card_time_filter, group_by="parent"): job_card_time_details[job_card_data.parent] = job_card_data res = [] @@ -172,12 +171,6 @@ def get_columns(filters): "options": "Operation", "width": 110 }, - { - "label": _("Employee Name"), - "fieldname": "employee_name", - "fieldtype": "Data", - "width": 110 - }, { "label": _("Total Completed Qty"), "fieldname": "total_completed_qty", diff --git a/erpnext/healthcare/doctype/drug_prescription/__init__.py b/erpnext/manufacturing/report/process_loss_report/__init__.py similarity index 100% rename from erpnext/healthcare/doctype/drug_prescription/__init__.py rename to erpnext/manufacturing/report/process_loss_report/__init__.py diff --git a/erpnext/stock/report/process_loss_report/process_loss_report.js b/erpnext/manufacturing/report/process_loss_report/process_loss_report.js similarity index 100% rename from erpnext/stock/report/process_loss_report/process_loss_report.js rename to erpnext/manufacturing/report/process_loss_report/process_loss_report.js diff --git a/erpnext/stock/report/process_loss_report/process_loss_report.json b/erpnext/manufacturing/report/process_loss_report/process_loss_report.json similarity index 83% rename from erpnext/stock/report/process_loss_report/process_loss_report.json rename to erpnext/manufacturing/report/process_loss_report/process_loss_report.json index afe4aff7f1c..7d3d13d98cf 100644 --- a/erpnext/stock/report/process_loss_report/process_loss_report.json +++ b/erpnext/manufacturing/report/process_loss_report/process_loss_report.json @@ -9,9 +9,9 @@ "filters": [], "idx": 0, "is_standard": "Yes", - "modified": "2021-08-24 16:38:15.233395", + "modified": "2021-10-20 22:03:57.606612", "modified_by": "Administrator", - "module": "Stock", + "module": "Manufacturing", "name": "Process Loss Report", "owner": "Administrator", "prepared_report": 0, @@ -21,9 +21,6 @@ "roles": [ { "role": "Manufacturing User" - }, - { - "role": "Stock User" } ] } \ No newline at end of file diff --git a/erpnext/stock/report/process_loss_report/process_loss_report.py b/erpnext/manufacturing/report/process_loss_report/process_loss_report.py similarity index 98% rename from erpnext/stock/report/process_loss_report/process_loss_report.py rename to erpnext/manufacturing/report/process_loss_report/process_loss_report.py index 499c49f893c..9b544dafa5f 100644 --- a/erpnext/stock/report/process_loss_report/process_loss_report.py +++ b/erpnext/manufacturing/report/process_loss_report/process_loss_report.py @@ -111,7 +111,7 @@ def run_query(query_args: QueryArgs) -> Data: {work_order_filter} GROUP BY se.work_order - """.format(**query_args), query_args, as_dict=1, debug=1) + """.format(**query_args), query_args, as_dict=1) def update_data_with_total_pl_value(data: Data) -> None: for row in data: diff --git a/erpnext/manufacturing/report/production_analytics/production_analytics.py b/erpnext/manufacturing/report/production_analytics/production_analytics.py index 9e0978aee7f..d4743d3a8ef 100644 --- a/erpnext/manufacturing/report/production_analytics/production_analytics.py +++ b/erpnext/manufacturing/report/production_analytics/production_analytics.py @@ -1,7 +1,6 @@ # Copyright (c) 2013, Frappe Technologies Pvt. Ltd. and contributors # For license information, please see license.txt -from __future__ import unicode_literals import frappe from frappe import _, scrub diff --git a/erpnext/manufacturing/report/production_plan_summary/production_plan_summary.py b/erpnext/manufacturing/report/production_plan_summary/production_plan_summary.py index 9a4d0c42db4..55b1a3f2f9a 100644 --- a/erpnext/manufacturing/report/production_plan_summary/production_plan_summary.py +++ b/erpnext/manufacturing/report/production_plan_summary/production_plan_summary.py @@ -1,7 +1,6 @@ # Copyright (c) 2013, Frappe Technologies Pvt. Ltd. and contributors # For license information, please see license.txt -from __future__ import unicode_literals import frappe from frappe.utils import flt @@ -29,8 +28,15 @@ def get_production_plan_item_details(filters, data, order_details): production_plan_doc = frappe.get_cached_doc("Production Plan", filters.get("production_plan")) for row in production_plan_doc.po_items: - work_order = frappe.get_cached_value("Work Order", {"production_plan_item": row.name, - "bom_no": row.bom_no, "production_item": row.item_code}, "name") + work_order = frappe.get_value( + "Work Order", + { + "production_plan_item": row.name, + "bom_no": row.bom_no, + "production_item": row.item_code + }, + "name" + ) if row.item_code not in itemwise_indent: itemwise_indent.setdefault(row.item_code, {}) @@ -41,10 +47,10 @@ def get_production_plan_item_details(filters, data, order_details): "item_name": frappe.get_cached_value("Item", row.item_code, "item_name"), "qty": row.planned_qty, "document_type": "Work Order", - "document_name": work_order, + "document_name": work_order or "", "bom_level": frappe.get_cached_value("BOM", row.bom_no, "bom_level"), - "produced_qty": order_details.get((work_order, row.item_code)).get("produced_qty"), - "pending_qty": flt(row.planned_qty) - flt(order_details.get((work_order, row.item_code)).get("produced_qty")) + "produced_qty": order_details.get((work_order, row.item_code), {}).get("produced_qty", 0), + "pending_qty": flt(row.planned_qty) - flt(order_details.get((work_order, row.item_code), {}).get("produced_qty", 0)) }) get_production_plan_sub_assembly_item_details(filters, row, production_plan_doc, data, order_details) @@ -55,11 +61,23 @@ def get_production_plan_sub_assembly_item_details(filters, row, production_plan_ subcontracted_item = (item.type_of_manufacturing == 'Subcontract') if subcontracted_item: - docname = frappe.get_cached_value("Purchase Order Item", - {"production_plan_sub_assembly_item": item.name, "docstatus": ("<", 2)}, "parent") + docname = frappe.get_value( + "Purchase Order Item", + { + "production_plan_sub_assembly_item": item.name, + "docstatus": ("<", 2) + }, + "parent" + ) else: - docname = frappe.get_cached_value("Work Order", - {"production_plan_sub_assembly_item": item.name, "docstatus": ("<", 2)}, "name") + docname = frappe.get_value( + "Work Order", + { + "production_plan_sub_assembly_item": item.name, + "docstatus": ("<", 2) + }, + "name" + ) data.append({ "indent": 1, @@ -67,10 +85,10 @@ def get_production_plan_sub_assembly_item_details(filters, row, production_plan_ "item_name": item.item_name, "qty": item.qty, "document_type": "Work Order" if not subcontracted_item else "Purchase Order", - "document_name": docname, + "document_name": docname or "", "bom_level": item.bom_level, - "produced_qty": order_details.get((docname, item.production_item)).get("produced_qty"), - "pending_qty": flt(item.qty) - flt(order_details.get((docname, item.production_item)).get("produced_qty")) + "produced_qty": order_details.get((docname, item.production_item), {}).get("produced_qty", 0), + "pending_qty": flt(item.qty) - flt(order_details.get((docname, item.production_item), {}).get("produced_qty", 0)) }) def get_work_order_details(filters, order_details): diff --git a/erpnext/manufacturing/report/production_planning_report/production_planning_report.py b/erpnext/manufacturing/report/production_planning_report/production_planning_report.py index e27270ae8b9..8368db6374b 100644 --- a/erpnext/manufacturing/report/production_planning_report/production_planning_report.py +++ b/erpnext/manufacturing/report/production_planning_report/production_planning_report.py @@ -1,7 +1,6 @@ # Copyright (c) 2013, Frappe Technologies Pvt. Ltd. and contributors # For license information, please see license.txt -from __future__ import unicode_literals import frappe from frappe import _ diff --git a/erpnext/manufacturing/report/quality_inspection_summary/quality_inspection_summary.py b/erpnext/manufacturing/report/quality_inspection_summary/quality_inspection_summary.py index 54df208346c..a0c4a43e90f 100644 --- a/erpnext/manufacturing/report/quality_inspection_summary/quality_inspection_summary.py +++ b/erpnext/manufacturing/report/quality_inspection_summary/quality_inspection_summary.py @@ -1,7 +1,6 @@ # Copyright (c) 2013, Frappe Technologies Pvt. Ltd. and contributors # For license information, please see license.txt -from __future__ import unicode_literals import frappe from frappe import _ diff --git a/erpnext/manufacturing/report/test_reports.py b/erpnext/manufacturing/report/test_reports.py new file mode 100644 index 00000000000..1de472659eb --- /dev/null +++ b/erpnext/manufacturing/report/test_reports.py @@ -0,0 +1,64 @@ +import unittest +from typing import List, Tuple + +import frappe + +from erpnext.tests.utils import ReportFilters, ReportName, execute_script_report + +DEFAULT_FILTERS = { + "company": "_Test Company", + "from_date": "2010-01-01", + "to_date": "2030-01-01", + "warehouse": "_Test Warehouse - _TC", +} + + +REPORT_FILTER_TEST_CASES: List[Tuple[ReportName, ReportFilters]] = [ + ("BOM Explorer", {"bom": frappe.get_last_doc("BOM").name}), + ("BOM Operations Time", {}), + ("BOM Stock Calculated", {"bom": frappe.get_last_doc("BOM").name, "qty_to_make": 2}), + ("BOM Stock Report", {"bom": frappe.get_last_doc("BOM").name, "qty_to_produce": 2}), + ("Cost of Poor Quality Report", {}), + ("Downtime Analysis", {}), + ( + "Exponential Smoothing Forecasting", + { + "based_on_document": "Sales Order", + "based_on_field": "Qty", + "no_of_years": 3, + "periodicity": "Yearly", + "smoothing_constant": 0.3, + }, + ), + ("Job Card Summary", {"fiscal_year": "2021-2022"}), + ("Production Analytics", {"range": "Monthly"}), + ("Quality Inspection Summary", {}), + ("Process Loss Report", {}), + ("Work Order Stock Report", {}), + ("Work Order Summary", {"fiscal_year": "2021-2022", "age": 0}), +] + + +if frappe.db.a_row_exists("Production Plan"): + REPORT_FILTER_TEST_CASES.append( + ("Production Plan Summary", {"production_plan": frappe.get_last_doc("Production Plan").name}) + ) + +OPTIONAL_FILTERS = { + "warehouse": "_Test Warehouse - _TC", + "item": "_Test Item", + "item_group": "_Test Item Group", +} + + +class TestManufacturingReports(unittest.TestCase): + def test_execute_all_manufacturing_reports(self): + """Test that all script report in manufacturing modules are executable with supported filters""" + for report, filter in REPORT_FILTER_TEST_CASES: + execute_script_report( + report_name=report, + module="Manufacturing", + filters=filter, + default_filters=DEFAULT_FILTERS, + optional_filters=OPTIONAL_FILTERS if filter.get("_optional") else None, + ) diff --git a/erpnext/manufacturing/report/work_order_stock_report/work_order_stock_report.py b/erpnext/manufacturing/report/work_order_stock_report/work_order_stock_report.py index 5b2e2620fd7..db0b239ae20 100644 --- a/erpnext/manufacturing/report/work_order_stock_report/work_order_stock_report.py +++ b/erpnext/manufacturing/report/work_order_stock_report/work_order_stock_report.py @@ -1,7 +1,6 @@ # Copyright (c) 2017, Velometro Mobility Inc and contributors # For license information, please see license.txt -from __future__ import unicode_literals import frappe from frappe.utils import cint diff --git a/erpnext/manufacturing/report/work_order_summary/work_order_summary.js b/erpnext/manufacturing/report/work_order_summary/work_order_summary.js index eb23f17c477..832be2301c1 100644 --- a/erpnext/manufacturing/report/work_order_summary/work_order_summary.js +++ b/erpnext/manufacturing/report/work_order_summary/work_order_summary.js @@ -51,7 +51,7 @@ frappe.query_reports["Work Order Summary"] = { label: __("Status"), fieldname: "status", fieldtype: "Select", - options: ["", "Not Started", "In Process", "Completed", "Stopped"] + options: ["", "Not Started", "In Process", "Completed", "Stopped", "Closed"] }, { label: __("Sales Orders"), diff --git a/erpnext/manufacturing/report/work_order_summary/work_order_summary.py b/erpnext/manufacturing/report/work_order_summary/work_order_summary.py index b65af33cec5..d7469ddfdd6 100644 --- a/erpnext/manufacturing/report/work_order_summary/work_order_summary.py +++ b/erpnext/manufacturing/report/work_order_summary/work_order_summary.py @@ -1,7 +1,7 @@ # Copyright (c) 2013, Frappe Technologies Pvt. Ltd. and contributors # For license information, please see license.txt -from __future__ import unicode_literals +from collections import defaultdict import frappe from frappe import _ @@ -59,21 +59,16 @@ def get_chart_data(data, filters): return get_chart_based_on_qty(data, filters) def get_chart_based_on_status(data): - labels = ["Completed", "In Process", "Stopped", "Not Started"] + labels = frappe.get_meta("Work Order").get_options("status").split("\n") + if "" in labels: + labels.remove("") - status_wise_data = { - "Not Started": 0, - "In Process": 0, - "Stopped": 0, - "Completed": 0, - "Draft": 0 - } + status_wise_data = defaultdict(int) for d in data: status_wise_data[d.status] += 1 - values = [status_wise_data["Completed"], status_wise_data["In Process"], - status_wise_data["Stopped"], status_wise_data["Not Started"]] + values = [status_wise_data[label] for label in labels] chart = { "data": { diff --git a/erpnext/manufacturing/workspace/manufacturing/manufacturing.json b/erpnext/manufacturing/workspace/manufacturing/manufacturing.json index 84eabcd2bdb..cfa80f8e9fc 100644 --- a/erpnext/manufacturing/workspace/manufacturing/manufacturing.json +++ b/erpnext/manufacturing/workspace/manufacturing/manufacturing.json @@ -1,5 +1,4 @@ { - "category": "", "charts": [ { "chart_name": "Produced Quantity" @@ -7,18 +6,12 @@ ], "content": "[{\"type\": \"onboarding\", \"data\": {\"onboarding_name\":\"Manufacturing\", \"col\": 12}}, {\"type\": \"chart\", \"data\": {\"chart_name\": null, \"col\": 12}}, {\"type\": \"spacer\", \"data\": {\"col\": 12}}, {\"type\": \"header\", \"data\": {\"text\": \"Your Shortcuts\", \"level\": 4, \"col\": 12}}, {\"type\": \"shortcut\", \"data\": {\"shortcut_name\": \"Item\", \"col\": 4}}, {\"type\": \"shortcut\", \"data\": {\"shortcut_name\": \"BOM\", \"col\": 4}}, {\"type\": \"shortcut\", \"data\": {\"shortcut_name\": \"Work Order\", \"col\": 4}}, {\"type\": \"shortcut\", \"data\": {\"shortcut_name\": \"Production Plan\", \"col\": 4}}, {\"type\": \"shortcut\", \"data\": {\"shortcut_name\": \"Forecasting\", \"col\": 4}}, {\"type\": \"shortcut\", \"data\": {\"shortcut_name\": \"Work Order Summary\", \"col\": 4}}, {\"type\": \"shortcut\", \"data\": {\"shortcut_name\": \"BOM Stock Report\", \"col\": 4}}, {\"type\": \"shortcut\", \"data\": {\"shortcut_name\": \"Production Planning Report\", \"col\": 4}}, {\"type\": \"shortcut\", \"data\": {\"shortcut_name\": \"Dashboard\", \"col\": 4}}, {\"type\": \"spacer\", \"data\": {\"col\": 12}}, {\"type\": \"header\", \"data\": {\"text\": \"Reports & Masters\", \"level\": 4, \"col\": 12}}, {\"type\": \"card\", \"data\": {\"card_name\": \"Production\", \"col\": 4}}, {\"type\": \"card\", \"data\": {\"card_name\": \"Bill of Materials\", \"col\": 4}}, {\"type\": \"card\", \"data\": {\"card_name\": \"Reports\", \"col\": 4}}, {\"type\": \"card\", \"data\": {\"card_name\": \"Tools\", \"col\": 4}}, {\"type\": \"card\", \"data\": {\"card_name\": \"Settings\", \"col\": 4}}]", "creation": "2020-03-02 17:11:37.032604", - "developer_mode_only": 0, - "disable_user_customization": 0, "docstatus": 0, "doctype": "Workspace", - "extends": "", - "extends_another_page": 0, "for_user": "", "hide_custom": 0, "icon": "organization", "idx": 0, - "is_default": 0, - "is_standard": 0, "label": "Manufacturing", "links": [ { @@ -304,15 +297,12 @@ "type": "Link" } ], - "modified": "2021-08-05 12:16:00.825741", + "modified": "2021-08-05 12:16:00.825742", "modified_by": "Administrator", "module": "Manufacturing", "name": "Manufacturing", - "onboarding": "Manufacturing", "owner": "Administrator", "parent_page": "", - "pin_to_bottom": 0, - "pin_to_top": 0, "public": 1, "restrict_to_domain": "Manufacturing", "roles": [], diff --git a/erpnext/modules.txt b/erpnext/modules.txt index 62f5dce8460..15a24a746f7 100644 --- a/erpnext/modules.txt +++ b/erpnext/modules.txt @@ -15,13 +15,11 @@ Portal Maintenance Education Regional -Healthcare Restaurant Agriculture ERPNext Integrations Non Profit Hotels -Hub Node Quality Management Communication Loan Management diff --git a/erpnext/non_profit/doctype/certification_application/certification_application.py b/erpnext/non_profit/doctype/certification_application/certification_application.py index ff400c81ae3..cbbe191fbac 100644 --- a/erpnext/non_profit/doctype/certification_application/certification_application.py +++ b/erpnext/non_profit/doctype/certification_application/certification_application.py @@ -1,8 +1,6 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2018, Frappe Technologies Pvt. Ltd. and contributors # For license information, please see license.txt -from __future__ import unicode_literals from frappe.model.document import Document diff --git a/erpnext/non_profit/doctype/certification_application/test_certification_application.py b/erpnext/non_profit/doctype/certification_application/test_certification_application.py index 5e1cbf85961..8687b4daf4b 100644 --- a/erpnext/non_profit/doctype/certification_application/test_certification_application.py +++ b/erpnext/non_profit/doctype/certification_application/test_certification_application.py @@ -1,7 +1,5 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2018, Frappe Technologies Pvt. Ltd. and Contributors # See license.txt -from __future__ import unicode_literals import unittest diff --git a/erpnext/non_profit/doctype/certified_consultant/certified_consultant.py b/erpnext/non_profit/doctype/certified_consultant/certified_consultant.py index 0cbc2088c96..47361cc39ea 100644 --- a/erpnext/non_profit/doctype/certified_consultant/certified_consultant.py +++ b/erpnext/non_profit/doctype/certified_consultant/certified_consultant.py @@ -1,8 +1,6 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2018, Frappe Technologies Pvt. Ltd. and contributors # For license information, please see license.txt -from __future__ import unicode_literals from frappe.model.document import Document diff --git a/erpnext/non_profit/doctype/certified_consultant/test_certified_consultant.py b/erpnext/non_profit/doctype/certified_consultant/test_certified_consultant.py index 29a73881a58..d10353c1e47 100644 --- a/erpnext/non_profit/doctype/certified_consultant/test_certified_consultant.py +++ b/erpnext/non_profit/doctype/certified_consultant/test_certified_consultant.py @@ -1,7 +1,5 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2018, Frappe Technologies Pvt. Ltd. and Contributors # See license.txt -from __future__ import unicode_literals import unittest diff --git a/erpnext/non_profit/doctype/chapter/chapter.py b/erpnext/non_profit/doctype/chapter/chapter.py index c5c9569e74e..c01b1ef3e42 100644 --- a/erpnext/non_profit/doctype/chapter/chapter.py +++ b/erpnext/non_profit/doctype/chapter/chapter.py @@ -1,8 +1,6 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2017, Frappe Technologies Pvt. Ltd. and contributors # For license information, please see license.txt -from __future__ import unicode_literals import frappe from frappe.website.website_generator import WebsiteGenerator diff --git a/erpnext/non_profit/doctype/chapter/test_chapter.py b/erpnext/non_profit/doctype/chapter/test_chapter.py index 04cdc277475..98601efcf23 100644 --- a/erpnext/non_profit/doctype/chapter/test_chapter.py +++ b/erpnext/non_profit/doctype/chapter/test_chapter.py @@ -1,7 +1,5 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2017, Frappe Technologies Pvt. Ltd. and Contributors # See license.txt -from __future__ import unicode_literals import unittest diff --git a/erpnext/non_profit/doctype/chapter_member/chapter_member.py b/erpnext/non_profit/doctype/chapter_member/chapter_member.py index 1638294de12..80c0446ee5a 100644 --- a/erpnext/non_profit/doctype/chapter_member/chapter_member.py +++ b/erpnext/non_profit/doctype/chapter_member/chapter_member.py @@ -1,8 +1,6 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2017, Frappe Technologies Pvt. Ltd. and contributors # For license information, please see license.txt -from __future__ import unicode_literals from frappe.model.document import Document diff --git a/erpnext/non_profit/doctype/donation/donation.py b/erpnext/non_profit/doctype/donation/donation.py index e4e2b4e7d65..54bc94b755c 100644 --- a/erpnext/non_profit/doctype/donation/donation.py +++ b/erpnext/non_profit/doctype/donation/donation.py @@ -1,13 +1,10 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2021, Frappe Technologies Pvt. Ltd. and contributors # For license information, please see license.txt -from __future__ import unicode_literals import json import frappe -import six from frappe import _ from frappe.email import sendmail_to_system_managers from frappe.model.document import Document @@ -85,7 +82,7 @@ def capture_razorpay_donations(*args, **kwargs): notify_failure(log) return { 'status': 'Failed', 'reason': e } - if isinstance(data, six.string_types): + if isinstance(data, str): data = json.loads(data) data = frappe._dict(data) @@ -171,7 +168,7 @@ def create_donor(payment): def get_company_for_donations(): company = frappe.db.get_single_value('Non Profit Settings', 'donation_company') if not company: - from erpnext.healthcare.setup import get_company + from erpnext.non_profit.utils import get_company company = get_company() return company diff --git a/erpnext/non_profit/doctype/donation/donation_dashboard.py b/erpnext/non_profit/doctype/donation/donation_dashboard.py index 4a16077ef47..492ad621718 100644 --- a/erpnext/non_profit/doctype/donation/donation_dashboard.py +++ b/erpnext/non_profit/doctype/donation/donation_dashboard.py @@ -1,5 +1,3 @@ -from __future__ import unicode_literals - from frappe import _ diff --git a/erpnext/non_profit/doctype/donation/test_donation.py b/erpnext/non_profit/doctype/donation/test_donation.py index 6b9ade9185c..5fa731a6aa3 100644 --- a/erpnext/non_profit/doctype/donation/test_donation.py +++ b/erpnext/non_profit/doctype/donation/test_donation.py @@ -1,7 +1,5 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2021, Frappe Technologies Pvt. Ltd. and Contributors # See license.txt -from __future__ import unicode_literals import unittest diff --git a/erpnext/non_profit/doctype/donor/donor.py b/erpnext/non_profit/doctype/donor/donor.py index a46163a0128..058321b1591 100644 --- a/erpnext/non_profit/doctype/donor/donor.py +++ b/erpnext/non_profit/doctype/donor/donor.py @@ -1,8 +1,6 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2017, Frappe Technologies Pvt. Ltd. and contributors # For license information, please see license.txt -from __future__ import unicode_literals from frappe.contacts.address_and_contact import load_address_and_contact from frappe.model.document import Document diff --git a/erpnext/non_profit/doctype/donor/test_donor.py b/erpnext/non_profit/doctype/donor/test_donor.py index 5ce01998bc3..fe591c8e72c 100644 --- a/erpnext/non_profit/doctype/donor/test_donor.py +++ b/erpnext/non_profit/doctype/donor/test_donor.py @@ -1,7 +1,5 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2017, Frappe Technologies Pvt. Ltd. and Contributors # See license.txt -from __future__ import unicode_literals import unittest diff --git a/erpnext/non_profit/doctype/donor_type/donor_type.py b/erpnext/non_profit/doctype/donor_type/donor_type.py index 4d34725d024..17dca899d56 100644 --- a/erpnext/non_profit/doctype/donor_type/donor_type.py +++ b/erpnext/non_profit/doctype/donor_type/donor_type.py @@ -1,8 +1,6 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2017, Frappe Technologies Pvt. Ltd. and contributors # For license information, please see license.txt -from __future__ import unicode_literals from frappe.model.document import Document diff --git a/erpnext/non_profit/doctype/donor_type/test_donor_type.py b/erpnext/non_profit/doctype/donor_type/test_donor_type.py index 7857ec5ad21..d433733ee25 100644 --- a/erpnext/non_profit/doctype/donor_type/test_donor_type.py +++ b/erpnext/non_profit/doctype/donor_type/test_donor_type.py @@ -1,7 +1,5 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2017, Frappe Technologies Pvt. Ltd. and Contributors # See license.txt -from __future__ import unicode_literals import unittest diff --git a/erpnext/non_profit/doctype/grant_application/grant_application.py b/erpnext/non_profit/doctype/grant_application/grant_application.py index 92a62563ab9..cc5e1b1442d 100644 --- a/erpnext/non_profit/doctype/grant_application/grant_application.py +++ b/erpnext/non_profit/doctype/grant_application/grant_application.py @@ -1,8 +1,6 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2017, Frappe Technologies Pvt. Ltd. and contributors # For license information, please see license.txt -from __future__ import unicode_literals import frappe from frappe import _ diff --git a/erpnext/non_profit/doctype/grant_application/test_grant_application.py b/erpnext/non_profit/doctype/grant_application/test_grant_application.py index d15809112ab..ef267d7af86 100644 --- a/erpnext/non_profit/doctype/grant_application/test_grant_application.py +++ b/erpnext/non_profit/doctype/grant_application/test_grant_application.py @@ -1,7 +1,5 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2017, Frappe Technologies Pvt. Ltd. and Contributors # See license.txt -from __future__ import unicode_literals import unittest diff --git a/erpnext/non_profit/doctype/member/member.py b/erpnext/non_profit/doctype/member/member.py index f7e7f105d55..4d80e57eccf 100644 --- a/erpnext/non_profit/doctype/member/member.py +++ b/erpnext/non_profit/doctype/member/member.py @@ -1,8 +1,6 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2017, Frappe Technologies Pvt. Ltd. and contributors # For license information, please see license.txt -from __future__ import unicode_literals import frappe from frappe import _ diff --git a/erpnext/non_profit/doctype/member/member_dashboard.py b/erpnext/non_profit/doctype/member/member_dashboard.py index ff929a59093..0e31e3ceb83 100644 --- a/erpnext/non_profit/doctype/member/member_dashboard.py +++ b/erpnext/non_profit/doctype/member/member_dashboard.py @@ -1,5 +1,3 @@ -from __future__ import unicode_literals - from frappe import _ diff --git a/erpnext/non_profit/doctype/member/test_member.py b/erpnext/non_profit/doctype/member/test_member.py index 38ad87f2f67..46f14ed1312 100644 --- a/erpnext/non_profit/doctype/member/test_member.py +++ b/erpnext/non_profit/doctype/member/test_member.py @@ -1,7 +1,5 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2017, Frappe Technologies Pvt. Ltd. and Contributors # See license.txt -from __future__ import unicode_literals import unittest diff --git a/erpnext/non_profit/doctype/membership/membership.py b/erpnext/non_profit/doctype/membership/membership.py index b65dc8e1e37..beb38e21108 100644 --- a/erpnext/non_profit/doctype/membership/membership.py +++ b/erpnext/non_profit/doctype/membership/membership.py @@ -1,14 +1,11 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2017, Frappe Technologies Pvt. Ltd. and contributors # For license information, please see license.txt -from __future__ import unicode_literals import json from datetime import datetime import frappe -import six from frappe import _ from frappe.email import sendmail_to_system_managers from frappe.model.document import Document @@ -345,7 +342,7 @@ def process_request_data(data): notify_failure(log) return {"status": "Failed", "reason": e} - if isinstance(data, six.string_types): + if isinstance(data, str): data = json.loads(data) data = frappe._dict(data) @@ -355,7 +352,7 @@ def process_request_data(data): def get_company_for_memberships(): company = frappe.db.get_single_value("Non Profit Settings", "company") if not company: - from erpnext.healthcare.setup import get_company + from erpnext.non_profit.utils import get_company company = get_company() return company diff --git a/erpnext/non_profit/doctype/membership/test_membership.py b/erpnext/non_profit/doctype/membership/test_membership.py index 5f52cdaca81..fbe344c6a15 100644 --- a/erpnext/non_profit/doctype/membership/test_membership.py +++ b/erpnext/non_profit/doctype/membership/test_membership.py @@ -1,7 +1,5 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2017, Frappe Technologies Pvt. Ltd. and Contributors # See license.txt -from __future__ import unicode_literals import unittest diff --git a/erpnext/non_profit/doctype/membership_type/membership_type.py b/erpnext/non_profit/doctype/membership_type/membership_type.py index 1b847d94b99..b4464215715 100644 --- a/erpnext/non_profit/doctype/membership_type/membership_type.py +++ b/erpnext/non_profit/doctype/membership_type/membership_type.py @@ -1,8 +1,6 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2017, Frappe Technologies Pvt. Ltd. and contributors # For license information, please see license.txt -from __future__ import unicode_literals import frappe from frappe import _ diff --git a/erpnext/non_profit/doctype/membership_type/test_membership_type.py b/erpnext/non_profit/doctype/membership_type/test_membership_type.py index 2503ba17d1c..98bc087acde 100644 --- a/erpnext/non_profit/doctype/membership_type/test_membership_type.py +++ b/erpnext/non_profit/doctype/membership_type/test_membership_type.py @@ -1,7 +1,5 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2017, Frappe Technologies Pvt. Ltd. and Contributors # See license.txt -from __future__ import unicode_literals import unittest diff --git a/erpnext/non_profit/doctype/non_profit_settings/non_profit_settings.py b/erpnext/non_profit/doctype/non_profit_settings/non_profit_settings.py index cb365cb6c10..ace66055427 100644 --- a/erpnext/non_profit/doctype/non_profit_settings/non_profit_settings.py +++ b/erpnext/non_profit/doctype/non_profit_settings/non_profit_settings.py @@ -1,8 +1,6 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2020, Frappe Technologies Pvt. Ltd. and contributors # For license information, please see license.txt -from __future__ import unicode_literals import frappe from frappe import _ diff --git a/erpnext/non_profit/doctype/non_profit_settings/test_non_profit_settings.py b/erpnext/non_profit/doctype/non_profit_settings/test_non_profit_settings.py index a0a54030cc9..51d1ba02eba 100644 --- a/erpnext/non_profit/doctype/non_profit_settings/test_non_profit_settings.py +++ b/erpnext/non_profit/doctype/non_profit_settings/test_non_profit_settings.py @@ -1,7 +1,5 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2020, Frappe Technologies Pvt. Ltd. and Contributors # See license.txt -from __future__ import unicode_literals # import frappe import unittest diff --git a/erpnext/non_profit/doctype/volunteer/test_volunteer.py b/erpnext/non_profit/doctype/volunteer/test_volunteer.py index 346eac56770..0a0ab2cf342 100644 --- a/erpnext/non_profit/doctype/volunteer/test_volunteer.py +++ b/erpnext/non_profit/doctype/volunteer/test_volunteer.py @@ -1,7 +1,5 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2017, Frappe Technologies Pvt. Ltd. and Contributors # See license.txt -from __future__ import unicode_literals import unittest diff --git a/erpnext/non_profit/doctype/volunteer/volunteer.py b/erpnext/non_profit/doctype/volunteer/volunteer.py index 6c9232b0ea1..b44d67dae39 100644 --- a/erpnext/non_profit/doctype/volunteer/volunteer.py +++ b/erpnext/non_profit/doctype/volunteer/volunteer.py @@ -1,8 +1,6 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2017, Frappe Technologies Pvt. Ltd. and contributors # For license information, please see license.txt -from __future__ import unicode_literals from frappe.contacts.address_and_contact import load_address_and_contact from frappe.model.document import Document diff --git a/erpnext/non_profit/doctype/volunteer_skill/volunteer_skill.py b/erpnext/non_profit/doctype/volunteer_skill/volunteer_skill.py index 3422ec2dec3..fe7251876d2 100644 --- a/erpnext/non_profit/doctype/volunteer_skill/volunteer_skill.py +++ b/erpnext/non_profit/doctype/volunteer_skill/volunteer_skill.py @@ -1,8 +1,6 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2017, Frappe Technologies Pvt. Ltd. and contributors # For license information, please see license.txt -from __future__ import unicode_literals from frappe.model.document import Document diff --git a/erpnext/non_profit/doctype/volunteer_type/test_volunteer_type.py b/erpnext/non_profit/doctype/volunteer_type/test_volunteer_type.py index 2c64d21bba4..cef27c83a56 100644 --- a/erpnext/non_profit/doctype/volunteer_type/test_volunteer_type.py +++ b/erpnext/non_profit/doctype/volunteer_type/test_volunteer_type.py @@ -1,7 +1,5 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2017, Frappe Technologies Pvt. Ltd. and Contributors # See license.txt -from __future__ import unicode_literals import unittest diff --git a/erpnext/non_profit/doctype/volunteer_type/volunteer_type.py b/erpnext/non_profit/doctype/volunteer_type/volunteer_type.py index 116f5d8b52f..3b1ae1a88e0 100644 --- a/erpnext/non_profit/doctype/volunteer_type/volunteer_type.py +++ b/erpnext/non_profit/doctype/volunteer_type/volunteer_type.py @@ -1,8 +1,6 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2017, Frappe Technologies Pvt. Ltd. and contributors # For license information, please see license.txt -from __future__ import unicode_literals from frappe.model.document import Document diff --git a/erpnext/non_profit/report/expiring_memberships/expiring_memberships.py b/erpnext/non_profit/report/expiring_memberships/expiring_memberships.py index 2167b651c34..3ddbfdc3b0d 100644 --- a/erpnext/non_profit/report/expiring_memberships/expiring_memberships.py +++ b/erpnext/non_profit/report/expiring_memberships/expiring_memberships.py @@ -1,7 +1,6 @@ # Copyright (c) 2013, Frappe Technologies Pvt. Ltd. and contributors # For license information, please see license.txt -from __future__ import unicode_literals import frappe from frappe import _ diff --git a/erpnext/non_profit/utils.py b/erpnext/non_profit/utils.py new file mode 100644 index 00000000000..47ea5f57832 --- /dev/null +++ b/erpnext/non_profit/utils.py @@ -0,0 +1,12 @@ +import frappe + + +def get_company(): + company = frappe.defaults.get_defaults().company + if company: + return company + else: + company = frappe.get_list("Company", limit=1) + if company: + return company[0].name + return None diff --git a/erpnext/non_profit/web_form/certification_application/certification_application.py b/erpnext/non_profit/web_form/certification_application/certification_application.py index f57de916dd1..02e3e933330 100644 --- a/erpnext/non_profit/web_form/certification_application/certification_application.py +++ b/erpnext/non_profit/web_form/certification_application/certification_application.py @@ -1,6 +1,3 @@ -from __future__ import unicode_literals - - def get_context(context): # do your magic here pass diff --git a/erpnext/non_profit/web_form/certification_application_usd/certification_application_usd.py b/erpnext/non_profit/web_form/certification_application_usd/certification_application_usd.py index f57de916dd1..02e3e933330 100644 --- a/erpnext/non_profit/web_form/certification_application_usd/certification_application_usd.py +++ b/erpnext/non_profit/web_form/certification_application_usd/certification_application_usd.py @@ -1,6 +1,3 @@ -from __future__ import unicode_literals - - def get_context(context): # do your magic here pass diff --git a/erpnext/non_profit/web_form/grant_application/grant_application.py b/erpnext/non_profit/web_form/grant_application/grant_application.py index dab0e9fda85..3dfb381f657 100644 --- a/erpnext/non_profit/web_form/grant_application/grant_application.py +++ b/erpnext/non_profit/web_form/grant_application/grant_application.py @@ -1,6 +1,3 @@ -from __future__ import unicode_literals - - def get_context(context): context.no_cache = True context.parents = [dict(label='View All ', diff --git a/erpnext/non_profit/workspace/non_profit/non_profit.json b/erpnext/non_profit/workspace/non_profit/non_profit.json index e6d4445945e..ba2f919d016 100644 --- a/erpnext/non_profit/workspace/non_profit/non_profit.json +++ b/erpnext/non_profit/workspace/non_profit/non_profit.json @@ -1,20 +1,13 @@ { - "category": "", "charts": [], "content": "[{\"type\": \"header\", \"data\": {\"text\": \"Your Shortcuts\", \"level\": 4, \"col\": 12}}, {\"type\": \"shortcut\", \"data\": {\"shortcut_name\": \"Member\", \"col\": 4}}, {\"type\": \"shortcut\", \"data\": {\"shortcut_name\": \"Non Profit Settings\", \"col\": 4}}, {\"type\": \"shortcut\", \"data\": {\"shortcut_name\": \"Membership\", \"col\": 4}}, {\"type\": \"shortcut\", \"data\": {\"shortcut_name\": \"Chapter\", \"col\": 4}}, {\"type\": \"shortcut\", \"data\": {\"shortcut_name\": \"Chapter Member\", \"col\": 4}}, {\"type\": \"spacer\", \"data\": {\"col\": 12}}, {\"type\": \"header\", \"data\": {\"text\": \"Reports & Masters\", \"level\": 4, \"col\": 12}}, {\"type\": \"card\", \"data\": {\"card_name\": \"Loan Management\", \"col\": 4}}, {\"type\": \"card\", \"data\": {\"card_name\": \"Grant Application\", \"col\": 4}}, {\"type\": \"card\", \"data\": {\"card_name\": \"Membership\", \"col\": 4}}, {\"type\": \"card\", \"data\": {\"card_name\": \"Volunteer\", \"col\": 4}}, {\"type\": \"card\", \"data\": {\"card_name\": \"Chapter\", \"col\": 4}}, {\"type\": \"card\", \"data\": {\"card_name\": \"Donation\", \"col\": 4}}, {\"type\": \"card\", \"data\": {\"card_name\": \"Tax Exemption Certification (India)\", \"col\": 4}}]", "creation": "2020-03-02 17:23:47.811421", - "developer_mode_only": 0, - "disable_user_customization": 0, "docstatus": 0, "doctype": "Workspace", - "extends": "", - "extends_another_page": 0, "for_user": "", "hide_custom": 0, "icon": "non-profit", "idx": 0, - "is_default": 0, - "is_standard": 0, "label": "Non Profit", "links": [ { @@ -238,15 +231,12 @@ "type": "Link" } ], - "modified": "2021-08-05 12:16:01.146206", + "modified": "2021-08-05 12:16:01.146207", "modified_by": "Administrator", "module": "Non Profit", "name": "Non Profit", - "onboarding": "", "owner": "Administrator", "parent_page": "", - "pin_to_bottom": 0, - "pin_to_top": 0, "public": 1, "restrict_to_domain": "Non Profit", "roles": [], diff --git a/erpnext/patches.txt b/erpnext/patches.txt index a03f90ea5b0..e475229125f 100644 --- a/erpnext/patches.txt +++ b/erpnext/patches.txt @@ -30,15 +30,12 @@ erpnext.patches.v11_0.add_default_email_template_for_leave erpnext.patches.v11_0.set_default_email_template_in_hr #08-06-2018 erpnext.patches.v11_0.uom_conversion_data #30-06-2018 erpnext.patches.v11_0.update_account_type_in_party_type -erpnext.patches.v11_0.rename_healthcare_doctype_and_fields erpnext.patches.v11_0.rename_supplier_type_to_supplier_group erpnext.patches.v10_1.transfer_subscription_to_auto_repeat erpnext.patches.v11_0.update_brand_in_item_price erpnext.patches.v11_0.create_default_success_action -erpnext.patches.v11_0.add_healthcare_service_unit_tree_root erpnext.patches.v11_0.rename_field_max_days_allowed erpnext.patches.v11_0.create_salary_structure_assignments -erpnext.patches.v11_0.rename_health_insurance erpnext.patches.v11_0.rebuild_tree_for_company erpnext.patches.v11_0.create_department_records_for_each_company erpnext.patches.v11_0.make_location_from_warehouse @@ -61,13 +58,7 @@ erpnext.patches.v11_0.set_department_for_doctypes erpnext.patches.v11_0.update_allow_transfer_for_manufacture erpnext.patches.v11_0.add_item_group_defaults erpnext.patches.v11_0.add_expense_claim_default_account -execute:frappe.delete_doc("Page", "hub") -erpnext.patches.v11_0.reset_publish_in_hub_for_all_items -erpnext.patches.v11_0.update_hub_url # 2018-08-31 # 2018-09-03 erpnext.patches.v11_0.make_job_card -erpnext.patches.v11_0.redesign_healthcare_billing_work_flow -erpnext.patches.v10_0.delete_hub_documents # 12-08-2018 -erpnext.patches.v11_0.rename_healthcare_fields erpnext.patches.v11_0.add_default_dispatch_notification_template erpnext.patches.v11_0.add_market_segments erpnext.patches.v11_0.add_sales_stages @@ -158,7 +149,6 @@ erpnext.patches.v12_0.set_cost_center_in_child_table_of_expense_claim erpnext.patches.v12_0.add_eway_bill_in_delivery_note erpnext.patches.v12_0.set_lead_title_field erpnext.patches.v12_0.set_permission_einvoicing -erpnext.patches.v12_0.set_published_in_hub_tracked_item erpnext.patches.v12_0.set_job_offer_applicant_email erpnext.patches.v12_0.create_irs_1099_field_united_states erpnext.patches.v12_0.move_bank_account_swift_number_to_bank @@ -169,7 +159,6 @@ erpnext.patches.v12_0.add_permission_in_lower_deduction erpnext.patches.v12_0.set_received_qty_in_material_request_as_per_stock_uom erpnext.patches.v12_0.rename_account_type_doctype erpnext.patches.v12_0.recalculate_requested_qty_in_bin -erpnext.patches.v12_0.update_healthcare_refactored_changes erpnext.patches.v12_0.set_total_batch_quantity erpnext.patches.v12_0.rename_mws_settings_fields erpnext.patches.v12_0.set_updated_purpose_in_pick_list @@ -178,7 +167,6 @@ erpnext.patches.v12_0.repost_stock_ledger_entries_for_target_warehouse erpnext.patches.v12_0.update_end_date_and_status_in_email_campaign erpnext.patches.v13_0.move_tax_slabs_from_payroll_period_to_income_tax_slab #123 erpnext.patches.v12_0.fix_quotation_expired_status -erpnext.patches.v12_0.update_appointment_reminder_scheduler_entry erpnext.patches.v12_0.rename_pos_closing_doctype erpnext.patches.v13_0.replace_pos_payment_mode_table #2020-12-29 erpnext.patches.v12_0.remove_duplicate_leave_ledger_entries #2020-05-22 @@ -196,7 +184,6 @@ execute:frappe.reload_doctype('Dashboard') execute:frappe.reload_doc('desk', 'doctype', 'number_card_link') execute:frappe.delete_doc_if_exists('Dashboard', 'Accounts') erpnext.patches.v13_0.update_actual_start_and_end_date_in_wo -erpnext.patches.v13_0.set_company_field_in_healthcare_doctypes #2021-04-16 erpnext.patches.v12_0.update_bom_in_so_mr execute:frappe.delete_doc("Report", "Department Analytics") execute:frappe.rename_doc("Desk Page", "Loan Management", "Loan", force=True) @@ -222,7 +209,6 @@ erpnext.patches.v12_0.fix_percent_complete_for_projects erpnext.patches.v13_0.delete_report_requested_items_to_order erpnext.patches.v12_0.update_item_tax_template_company erpnext.patches.v13_0.move_branch_code_to_bank_account -erpnext.patches.v13_0.healthcare_lab_module_rename_doctypes erpnext.patches.v13_0.add_standard_navbar_items #2021-03-24 erpnext.patches.v13_0.stock_entry_enhancements erpnext.patches.v12_0.update_state_code_for_daman_and_diu @@ -236,7 +222,6 @@ erpnext.patches.v13_0.set_youtube_video_id erpnext.patches.v13_0.set_app_name erpnext.patches.v13_0.print_uom_after_quantity_patch erpnext.patches.v13_0.set_payment_channel_in_payment_gateway_account -erpnext.patches.v13_0.create_healthcare_custom_fields_in_stock_entry_detail erpnext.patches.v13_0.updates_for_multi_currency_payroll erpnext.patches.v13_0.update_reason_for_resignation_in_employee execute:frappe.delete_doc("Report", "Quoted Item Comparison") @@ -251,19 +236,17 @@ erpnext.patches.v13_0.create_uae_pos_invoice_fields erpnext.patches.v13_0.update_project_template_tasks erpnext.patches.v13_0.set_company_in_leave_ledger_entry erpnext.patches.v13_0.convert_qi_parameter_to_link_field -erpnext.patches.v13_0.setup_patient_history_settings_for_standard_doctypes erpnext.patches.v13_0.add_naming_series_to_old_projects # 1-02-2021 erpnext.patches.v13_0.update_payment_terms_outstanding erpnext.patches.v12_0.add_state_code_for_ladakh erpnext.patches.v13_0.item_reposting_for_incorrect_sl_and_gl erpnext.patches.v13_0.delete_old_bank_reconciliation_doctypes -erpnext.patches.v12_0.update_vehicle_no_reqd_condition +erpnext.patches.v13_0.update_vehicle_no_reqd_condition erpnext.patches.v13_0.setup_fields_for_80g_certificate_and_donation erpnext.patches.v13_0.rename_membership_settings_to_non_profit_settings erpnext.patches.v13_0.setup_gratuity_rule_for_india_and_uae erpnext.patches.v13_0.setup_uae_vat_fields execute:frappe.db.set_value('System Settings', None, 'app_name', 'ERPNext') -erpnext.patches.v13_0.rename_discharge_date_in_ip_record erpnext.patches.v12_0.create_taxable_value_field erpnext.patches.v12_0.add_gst_category_in_delivery_note erpnext.patches.v12_0.purchase_receipt_status @@ -298,9 +281,34 @@ erpnext.patches.v13_0.shopify_deprecation_warning erpnext.patches.v13_0.migrate_stripe_api erpnext.patches.v13_0.reset_clearance_date_for_intracompany_payment_entries erpnext.patches.v13_0.einvoicing_deprecation_warning -erpnext.patches.v13_0.custom_fields_for_taxjar_integration +execute:frappe.reload_doc("erpnext_integrations", "doctype", "TaxJar Settings") +execute:frappe.reload_doc("erpnext_integrations", "doctype", "Product Tax Category") erpnext.patches.v14_0.delete_einvoicing_doctypes +erpnext.patches.v13_0.custom_fields_for_taxjar_integration #08-11-2021 erpnext.patches.v13_0.set_operation_time_based_on_operating_cost erpnext.patches.v13_0.validate_options_for_data_field erpnext.patches.v13_0.create_gst_payment_entry_fields erpnext.patches.v14_0.delete_shopify_doctypes +erpnext.patches.v13_0.fix_invoice_statuses +erpnext.patches.v13_0.replace_supplier_item_group_with_party_specific_item +erpnext.patches.v13_0.update_dates_in_tax_withholding_category +erpnext.patches.v14_0.update_opportunity_currency_fields +erpnext.patches.v13_0.gst_fields_for_pos_invoice +erpnext.patches.v13_0.create_accounting_dimensions_in_pos_doctypes +erpnext.patches.v13_0.trim_sales_invoice_custom_field_length +erpnext.patches.v13_0.create_custom_field_for_finance_book +erpnext.patches.v13_0.modify_invalid_gain_loss_gl_entries #2 +erpnext.patches.v13_0.fix_additional_cost_in_mfg_stock_entry +erpnext.patches.v13_0.set_status_in_maintenance_schedule_table +erpnext.patches.v13_0.add_default_interview_notification_templates +erpnext.patches.v13_0.enable_scheduler_job_for_item_reposting +erpnext.patches.v13_0.requeue_failed_reposts +erpnext.patches.v13_0.update_job_card_status +erpnext.patches.v12_0.update_production_plan_status +erpnext.patches.v13_0.healthcare_deprecation_warning +erpnext.patches.v13_0.item_naming_series_not_mandatory +erpnext.patches.v14_0.delete_healthcare_doctypes +erpnext.patches.v13_0.update_category_in_ltds_certificate +erpnext.patches.v13_0.create_pan_field_for_india #2 +erpnext.patches.v14_0.delete_hub_doctypes +erpnext.patches.v13_0.create_ksa_vat_custom_fields diff --git a/erpnext/patches/__init__.py b/erpnext/patches/__init__.py index baffc488252..e69de29bb2d 100644 --- a/erpnext/patches/__init__.py +++ b/erpnext/patches/__init__.py @@ -1 +0,0 @@ -from __future__ import unicode_literals diff --git a/erpnext/patches/v10_0/add_default_cash_flow_mappers.py b/erpnext/patches/v10_0/add_default_cash_flow_mappers.py index 5c28597faad..165ca0243bf 100644 --- a/erpnext/patches/v10_0/add_default_cash_flow_mappers.py +++ b/erpnext/patches/v10_0/add_default_cash_flow_mappers.py @@ -1,7 +1,6 @@ # Copyright (c) 2017, Frappe and Contributors # License: GNU General Public License v3. See license.txt -from __future__ import unicode_literals import frappe diff --git a/erpnext/patches/v10_0/delete_hub_documents.py b/erpnext/patches/v10_0/delete_hub_documents.py deleted file mode 100644 index 16c7abfc978..00000000000 --- a/erpnext/patches/v10_0/delete_hub_documents.py +++ /dev/null @@ -1,19 +0,0 @@ -from __future__ import unicode_literals - -import frappe - - -def execute(): - for dt, dn in (("Page", "Hub"), ("DocType", "Hub Settings"), ("DocType", "Hub Category")): - frappe.delete_doc(dt, dn, ignore_missing=True) - - if frappe.db.exists("DocType", "Data Migration Plan"): - data_migration_plans = frappe.get_all("Data Migration Plan", filters={"module": 'Hub Node'}) - for plan in data_migration_plans: - plan_doc = frappe.get_doc("Data Migration Plan", plan.name) - for m in plan_doc.get("mappings"): - frappe.delete_doc("Data Migration Mapping", m.mapping, force=True) - docs = frappe.get_all("Data Migration Run", filters={"data_migration_plan": plan.name}) - for doc in docs: - frappe.delete_doc("Data Migration Run", doc.name) - frappe.delete_doc("Data Migration Plan", plan.name) diff --git a/erpnext/patches/v10_0/fichier_des_ecritures_comptables_for_france.py b/erpnext/patches/v10_0/fichier_des_ecritures_comptables_for_france.py index a3e49577a33..cdf5ba29141 100644 --- a/erpnext/patches/v10_0/fichier_des_ecritures_comptables_for_france.py +++ b/erpnext/patches/v10_0/fichier_des_ecritures_comptables_for_france.py @@ -1,7 +1,6 @@ # Copyright (c) 2018, Frappe and Contributors # License: GNU General Public License v3. See license.txt -from __future__ import unicode_literals import frappe diff --git a/erpnext/patches/v10_0/item_barcode_childtable_migrate.py b/erpnext/patches/v10_0/item_barcode_childtable_migrate.py index ec9c6c3b760..ffff95d223c 100644 --- a/erpnext/patches/v10_0/item_barcode_childtable_migrate.py +++ b/erpnext/patches/v10_0/item_barcode_childtable_migrate.py @@ -1,7 +1,6 @@ # Copyright (c) 2017, Frappe and Contributors # License: GNU General Public License v3. See license.txt -from __future__ import unicode_literals import frappe diff --git a/erpnext/patches/v10_0/migrate_daily_work_summary_settings_to_daily_work_summary_group.py b/erpnext/patches/v10_0/migrate_daily_work_summary_settings_to_daily_work_summary_group.py index a3c61a5294a..fd511849b2b 100644 --- a/erpnext/patches/v10_0/migrate_daily_work_summary_settings_to_daily_work_summary_group.py +++ b/erpnext/patches/v10_0/migrate_daily_work_summary_settings_to_daily_work_summary_group.py @@ -1,7 +1,6 @@ # Copyright (c) 2018, Frappe and Contributors # License: GNU General Public License v3. See license.txt -from __future__ import unicode_literals import frappe diff --git a/erpnext/patches/v10_0/rename_offer_letter_to_job_offer.py b/erpnext/patches/v10_0/rename_offer_letter_to_job_offer.py index 4fc419e302c..a2deab62258 100644 --- a/erpnext/patches/v10_0/rename_offer_letter_to_job_offer.py +++ b/erpnext/patches/v10_0/rename_offer_letter_to_job_offer.py @@ -1,5 +1,3 @@ -from __future__ import unicode_literals - import frappe diff --git a/erpnext/patches/v10_0/rename_price_to_rate_in_pricing_rule.py b/erpnext/patches/v10_0/rename_price_to_rate_in_pricing_rule.py index 1b8c6fb7ea5..525d1ff2042 100644 --- a/erpnext/patches/v10_0/rename_price_to_rate_in_pricing_rule.py +++ b/erpnext/patches/v10_0/rename_price_to_rate_in_pricing_rule.py @@ -1,5 +1,3 @@ -from __future__ import unicode_literals - import frappe from frappe.model.utils.rename_field import rename_field diff --git a/erpnext/patches/v10_0/set_currency_in_pricing_rule.py b/erpnext/patches/v10_0/set_currency_in_pricing_rule.py index 2a3f1c03bde..3f3d42400ab 100644 --- a/erpnext/patches/v10_0/set_currency_in_pricing_rule.py +++ b/erpnext/patches/v10_0/set_currency_in_pricing_rule.py @@ -1,5 +1,3 @@ -from __future__ import unicode_literals - import frappe diff --git a/erpnext/patches/v10_0/update_translatable_fields.py b/erpnext/patches/v10_0/update_translatable_fields.py index 2c55a052173..471f53704de 100644 --- a/erpnext/patches/v10_0/update_translatable_fields.py +++ b/erpnext/patches/v10_0/update_translatable_fields.py @@ -1,7 +1,3 @@ -#-*- coding: utf-8 -*- - -from __future__ import unicode_literals - import frappe diff --git a/erpnext/patches/v10_1/transfer_subscription_to_auto_repeat.py b/erpnext/patches/v10_1/transfer_subscription_to_auto_repeat.py index 2d5b0c5bd4a..6530b815cc1 100644 --- a/erpnext/patches/v10_1/transfer_subscription_to_auto_repeat.py +++ b/erpnext/patches/v10_1/transfer_subscription_to_auto_repeat.py @@ -1,5 +1,3 @@ -from __future__ import unicode_literals - import frappe from frappe.model.utils.rename_field import rename_field diff --git a/erpnext/patches/v11_0/add_default_dispatch_notification_template.py b/erpnext/patches/v11_0/add_default_dispatch_notification_template.py index 197b3b72676..08006ad01b1 100644 --- a/erpnext/patches/v11_0/add_default_dispatch_notification_template.py +++ b/erpnext/patches/v11_0/add_default_dispatch_notification_template.py @@ -1,5 +1,3 @@ -from __future__ import unicode_literals - import os import frappe diff --git a/erpnext/patches/v11_0/add_default_email_template_for_leave.py b/erpnext/patches/v11_0/add_default_email_template_for_leave.py index f8538df2ef2..fdf30469bf0 100644 --- a/erpnext/patches/v11_0/add_default_email_template_for_leave.py +++ b/erpnext/patches/v11_0/add_default_email_template_for_leave.py @@ -1,5 +1,3 @@ -from __future__ import unicode_literals - import os import frappe diff --git a/erpnext/patches/v11_0/add_expense_claim_default_account.py b/erpnext/patches/v11_0/add_expense_claim_default_account.py index 74b93efbf80..f5658c5b931 100644 --- a/erpnext/patches/v11_0/add_expense_claim_default_account.py +++ b/erpnext/patches/v11_0/add_expense_claim_default_account.py @@ -1,5 +1,3 @@ -from __future__ import unicode_literals - import frappe diff --git a/erpnext/patches/v11_0/add_healthcare_service_unit_tree_root.py b/erpnext/patches/v11_0/add_healthcare_service_unit_tree_root.py deleted file mode 100644 index 9bb91dc14c1..00000000000 --- a/erpnext/patches/v11_0/add_healthcare_service_unit_tree_root.py +++ /dev/null @@ -1,22 +0,0 @@ -from __future__ import unicode_literals - -import frappe -from frappe import _ - - -def execute(): - """ assign lft and rgt appropriately """ - if "Healthcare" not in frappe.get_active_domains(): - return - - frappe.reload_doc("healthcare", "doctype", "healthcare_service_unit") - frappe.reload_doc("healthcare", "doctype", "healthcare_service_unit_type") - company = frappe.get_value("Company", {"domain": "Healthcare"}, "name") - - if company: - frappe.get_doc({ - 'doctype': 'Healthcare Service Unit', - 'healthcare_service_unit_name': _('All Healthcare Service Units'), - 'is_group': 1, - 'company': company - }).insert(ignore_permissions=True) diff --git a/erpnext/patches/v11_0/add_index_on_nestedset_doctypes.py b/erpnext/patches/v11_0/add_index_on_nestedset_doctypes.py index 08ad855e5e2..7c99f580f7c 100644 --- a/erpnext/patches/v11_0/add_index_on_nestedset_doctypes.py +++ b/erpnext/patches/v11_0/add_index_on_nestedset_doctypes.py @@ -1,7 +1,6 @@ # Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors # License: GNU General Public License v3. See license.txt -from __future__ import unicode_literals import frappe diff --git a/erpnext/patches/v11_0/add_item_group_defaults.py b/erpnext/patches/v11_0/add_item_group_defaults.py index 6849b27feee..026047a9612 100644 --- a/erpnext/patches/v11_0/add_item_group_defaults.py +++ b/erpnext/patches/v11_0/add_item_group_defaults.py @@ -1,7 +1,6 @@ # Copyright (c) 2018, Frappe and Contributors # License: GNU General Public License v3. See license.txt -from __future__ import unicode_literals import frappe diff --git a/erpnext/patches/v11_0/add_market_segments.py b/erpnext/patches/v11_0/add_market_segments.py index e7cc7d1117c..6dcbf99e16a 100644 --- a/erpnext/patches/v11_0/add_market_segments.py +++ b/erpnext/patches/v11_0/add_market_segments.py @@ -1,5 +1,3 @@ -from __future__ import unicode_literals - import frappe from erpnext.setup.setup_wizard.operations.install_fixtures import add_market_segments diff --git a/erpnext/patches/v11_0/add_sales_stages.py b/erpnext/patches/v11_0/add_sales_stages.py index 23e48747b82..064b72195f6 100644 --- a/erpnext/patches/v11_0/add_sales_stages.py +++ b/erpnext/patches/v11_0/add_sales_stages.py @@ -1,5 +1,3 @@ -from __future__ import unicode_literals - import frappe from erpnext.setup.setup_wizard.operations.install_fixtures import add_sale_stages diff --git a/erpnext/patches/v11_0/check_buying_selling_in_currency_exchange.py b/erpnext/patches/v11_0/check_buying_selling_in_currency_exchange.py index 5eaf21220bd..573021270df 100644 --- a/erpnext/patches/v11_0/check_buying_selling_in_currency_exchange.py +++ b/erpnext/patches/v11_0/check_buying_selling_in_currency_exchange.py @@ -1,5 +1,3 @@ -from __future__ import unicode_literals - import frappe diff --git a/erpnext/patches/v11_0/create_default_success_action.py b/erpnext/patches/v11_0/create_default_success_action.py index 4a598371f82..e7b412cc5f2 100644 --- a/erpnext/patches/v11_0/create_default_success_action.py +++ b/erpnext/patches/v11_0/create_default_success_action.py @@ -1,5 +1,3 @@ -from __future__ import unicode_literals - import frappe from erpnext.setup.install import create_default_success_action diff --git a/erpnext/patches/v11_0/create_department_records_for_each_company.py b/erpnext/patches/v11_0/create_department_records_for_each_company.py index 7799a650405..034418c1371 100644 --- a/erpnext/patches/v11_0/create_department_records_for_each_company.py +++ b/erpnext/patches/v11_0/create_department_records_for_each_company.py @@ -1,5 +1,3 @@ -from __future__ import unicode_literals - import frappe from frappe import _ from frappe.utils.nestedset import rebuild_tree diff --git a/erpnext/patches/v11_0/create_salary_structure_assignments.py b/erpnext/patches/v11_0/create_salary_structure_assignments.py index c3cc9b6d309..823eca19b07 100644 --- a/erpnext/patches/v11_0/create_salary_structure_assignments.py +++ b/erpnext/patches/v11_0/create_salary_structure_assignments.py @@ -1,7 +1,6 @@ # Copyright (c) 2017, Frappe and Contributors # License: GNU General Public License v3. See license.txt -from __future__ import unicode_literals from datetime import datetime diff --git a/erpnext/patches/v11_0/drop_column_max_days_allowed.py b/erpnext/patches/v11_0/drop_column_max_days_allowed.py index e45d01cef58..f0803cb5c7f 100644 --- a/erpnext/patches/v11_0/drop_column_max_days_allowed.py +++ b/erpnext/patches/v11_0/drop_column_max_days_allowed.py @@ -1,5 +1,3 @@ -from __future__ import unicode_literals - import frappe diff --git a/erpnext/patches/v11_0/ewaybill_fields_gst_india.py b/erpnext/patches/v11_0/ewaybill_fields_gst_india.py index a59291ce420..5974e27059e 100644 --- a/erpnext/patches/v11_0/ewaybill_fields_gst_india.py +++ b/erpnext/patches/v11_0/ewaybill_fields_gst_india.py @@ -1,5 +1,3 @@ -from __future__ import unicode_literals - import frappe from erpnext.regional.india.setup import make_custom_fields diff --git a/erpnext/patches/v11_0/hr_ux_cleanups.py b/erpnext/patches/v11_0/hr_ux_cleanups.py index b09f4a7e7f2..43c85042942 100644 --- a/erpnext/patches/v11_0/hr_ux_cleanups.py +++ b/erpnext/patches/v11_0/hr_ux_cleanups.py @@ -1,5 +1,3 @@ -from __future__ import unicode_literals - import frappe diff --git a/erpnext/patches/v11_0/inter_state_field_for_gst.py b/erpnext/patches/v11_0/inter_state_field_for_gst.py index fa83af00655..a1f159483bd 100644 --- a/erpnext/patches/v11_0/inter_state_field_for_gst.py +++ b/erpnext/patches/v11_0/inter_state_field_for_gst.py @@ -1,5 +1,3 @@ -from __future__ import unicode_literals - import frappe from erpnext.regional.india.setup import make_custom_fields diff --git a/erpnext/patches/v11_0/make_asset_finance_book_against_old_entries.py b/erpnext/patches/v11_0/make_asset_finance_book_against_old_entries.py index 1d3f8c1204d..cd3869b3600 100644 --- a/erpnext/patches/v11_0/make_asset_finance_book_against_old_entries.py +++ b/erpnext/patches/v11_0/make_asset_finance_book_against_old_entries.py @@ -1,7 +1,6 @@ # Copyright (c) 2017, Frappe and Contributors # License: GNU General Public License v3. See license.txt -from __future__ import unicode_literals import frappe diff --git a/erpnext/patches/v11_0/make_italian_localization_fields.py b/erpnext/patches/v11_0/make_italian_localization_fields.py index 994df721c25..8ff23a50d4b 100644 --- a/erpnext/patches/v11_0/make_italian_localization_fields.py +++ b/erpnext/patches/v11_0/make_italian_localization_fields.py @@ -1,7 +1,6 @@ # Copyright (c) 2017, Frappe and Contributors # License: GNU General Public License v3. See license.txt -from __future__ import unicode_literals import frappe diff --git a/erpnext/patches/v11_0/make_job_card.py b/erpnext/patches/v11_0/make_job_card.py index e361d5a8381..120e018805a 100644 --- a/erpnext/patches/v11_0/make_job_card.py +++ b/erpnext/patches/v11_0/make_job_card.py @@ -1,7 +1,6 @@ # Copyright (c) 2017, Frappe and Contributors # License: GNU General Public License v3. See license.txt -from __future__ import unicode_literals import frappe diff --git a/erpnext/patches/v11_0/make_location_from_warehouse.py b/erpnext/patches/v11_0/make_location_from_warehouse.py index e855b3ee5e1..ef6262be15e 100644 --- a/erpnext/patches/v11_0/make_location_from_warehouse.py +++ b/erpnext/patches/v11_0/make_location_from_warehouse.py @@ -1,7 +1,6 @@ # Copyright (c) 2017, Frappe and Contributors # License: GNU General Public License v3. See license.txt -from __future__ import unicode_literals import frappe from frappe.utils.nestedset import rebuild_tree diff --git a/erpnext/patches/v11_0/make_quality_inspection_template.py b/erpnext/patches/v11_0/make_quality_inspection_template.py index 1c3d34ee208..58c9fb9239f 100644 --- a/erpnext/patches/v11_0/make_quality_inspection_template.py +++ b/erpnext/patches/v11_0/make_quality_inspection_template.py @@ -1,7 +1,6 @@ # Copyright (c) 2017, Frappe and Contributors # License: GNU General Public License v3. See license.txt -from __future__ import unicode_literals import frappe diff --git a/erpnext/patches/v11_0/merge_land_unit_with_location.py b/erpnext/patches/v11_0/merge_land_unit_with_location.py index 7845da255a8..e1d0b127b9d 100644 --- a/erpnext/patches/v11_0/merge_land_unit_with_location.py +++ b/erpnext/patches/v11_0/merge_land_unit_with_location.py @@ -1,7 +1,6 @@ # Copyright (c) 2018, Frappe and Contributors # License: GNU General Public License v3. See license.txt -from __future__ import unicode_literals import frappe from frappe.model.utils.rename_field import rename_field diff --git a/erpnext/patches/v11_0/move_item_defaults_to_child_table_for_multicompany.py b/erpnext/patches/v11_0/move_item_defaults_to_child_table_for_multicompany.py index 42fdf1358ad..bfc3fbc6084 100644 --- a/erpnext/patches/v11_0/move_item_defaults_to_child_table_for_multicompany.py +++ b/erpnext/patches/v11_0/move_item_defaults_to_child_table_for_multicompany.py @@ -1,7 +1,6 @@ # Copyright (c) 2018, Frappe and Contributors # License: GNU General Public License v3. See license.txt -from __future__ import unicode_literals import frappe diff --git a/erpnext/patches/v11_0/move_leave_approvers_from_employee.py b/erpnext/patches/v11_0/move_leave_approvers_from_employee.py index accfa5ecb39..80e5ef7f37a 100644 --- a/erpnext/patches/v11_0/move_leave_approvers_from_employee.py +++ b/erpnext/patches/v11_0/move_leave_approvers_from_employee.py @@ -1,5 +1,3 @@ -from __future__ import unicode_literals - import frappe from frappe.model.utils.rename_field import rename_field diff --git a/erpnext/patches/v11_0/rebuild_tree_for_company.py b/erpnext/patches/v11_0/rebuild_tree_for_company.py index 6caca4730c2..cad9c6cd788 100644 --- a/erpnext/patches/v11_0/rebuild_tree_for_company.py +++ b/erpnext/patches/v11_0/rebuild_tree_for_company.py @@ -1,5 +1,3 @@ -from __future__ import unicode_literals - import frappe from frappe.utils.nestedset import rebuild_tree diff --git a/erpnext/patches/v11_0/redesign_healthcare_billing_work_flow.py b/erpnext/patches/v11_0/redesign_healthcare_billing_work_flow.py deleted file mode 100644 index b1ed0f598c6..00000000000 --- a/erpnext/patches/v11_0/redesign_healthcare_billing_work_flow.py +++ /dev/null @@ -1,69 +0,0 @@ -from __future__ import unicode_literals - -import frappe -from frappe.custom.doctype.custom_field.custom_field import create_custom_fields -from frappe.modules import get_doctype_module, scrub - -from erpnext.domains.healthcare import data - -sales_invoice_referenced_doc = { - "Patient Appointment": "sales_invoice", - "Patient Encounter": "invoice", - "Lab Test": "invoice", - "Lab Prescription": "invoice", - "Sample Collection": "invoice" -} - -def execute(): - frappe.reload_doc('accounts', 'doctype', 'loyalty_program') - frappe.reload_doc('accounts', 'doctype', 'sales_invoice_item') - - if "Healthcare" not in frappe.get_active_domains(): - return - - healthcare_custom_field_in_sales_invoice() - for si_ref_doc in sales_invoice_referenced_doc: - if frappe.db.exists('DocType', si_ref_doc): - frappe.reload_doc(get_doctype_module(si_ref_doc), 'doctype', scrub(si_ref_doc)) - - if frappe.db.has_column(si_ref_doc, sales_invoice_referenced_doc[si_ref_doc]) \ - and frappe.db.has_column(si_ref_doc, 'invoiced'): - # Set Reference DocType and Reference Docname - doc_list = frappe.db.sql(""" - select name from `tab{0}` - where {1} is not null - """.format(si_ref_doc, sales_invoice_referenced_doc[si_ref_doc])) - if doc_list: - frappe.reload_doc(get_doctype_module("Sales Invoice"), 'doctype', 'sales_invoice') - for doc_id in doc_list: - invoice_id = frappe.db.get_value(si_ref_doc, doc_id[0], sales_invoice_referenced_doc[si_ref_doc]) - if frappe.db.exists("Sales Invoice", invoice_id): - if si_ref_doc == "Lab Test": - template = frappe.db.get_value("Lab Test", doc_id[0], "template") - if template: - item = frappe.db.get_value("Lab Test Template", template, "item") - if item: - frappe.db.sql("""update `tabSales Invoice Item` set reference_dt = '{0}', - reference_dn = '{1}' where parent = '{2}' and item_code='{3}'""".format\ - (si_ref_doc, doc_id[0], invoice_id, item)) - else: - invoice = frappe.get_doc("Sales Invoice", invoice_id) - for item_line in invoice.items: - if not item_line.reference_dn: - item_line.db_set({"reference_dt":si_ref_doc, "reference_dn": doc_id[0]}) - break - # Documents mark invoiced for submitted sales invoice - frappe.db.sql("""update `tab{0}` doc, `tabSales Invoice` si - set doc.invoiced = 1 where si.docstatus = 1 and doc.{1} = si.name - """.format(si_ref_doc, sales_invoice_referenced_doc[si_ref_doc])) - -def healthcare_custom_field_in_sales_invoice(): - frappe.reload_doc('healthcare', 'doctype', 'patient') - frappe.reload_doc('healthcare', 'doctype', 'healthcare_practitioner') - if data['custom_fields']: - create_custom_fields(data['custom_fields']) - - frappe.db.sql(""" - delete from `tabCustom Field` - where fieldname = 'appointment' and options = 'Patient Appointment' - """) diff --git a/erpnext/patches/v11_0/refactor_autoname_naming.py b/erpnext/patches/v11_0/refactor_autoname_naming.py index dd5cb639b1b..1c4d8f1f79f 100644 --- a/erpnext/patches/v11_0/refactor_autoname_naming.py +++ b/erpnext/patches/v11_0/refactor_autoname_naming.py @@ -1,7 +1,6 @@ # Copyright (c) 2018, Frappe Technologies Pvt. Ltd. and Contributors # License: GNU General Public License v3. See license.txt -from __future__ import print_function, unicode_literals import frappe from frappe.custom.doctype.property_setter.property_setter import make_property_setter diff --git a/erpnext/patches/v11_0/refactor_naming_series.py b/erpnext/patches/v11_0/refactor_naming_series.py index 9f231edea73..e0aa004e476 100644 --- a/erpnext/patches/v11_0/refactor_naming_series.py +++ b/erpnext/patches/v11_0/refactor_naming_series.py @@ -1,7 +1,6 @@ # Copyright (c) 2018, Frappe Technologies Pvt. Ltd. and Contributors # License: GNU General Public License v3. See license.txt -from __future__ import print_function, unicode_literals import frappe from frappe.custom.doctype.property_setter.property_setter import make_property_setter @@ -15,7 +14,6 @@ doctype_series_map = { 'Blanket Order': 'MFG-BLR-.YYYY.-', 'C-Form': 'ACC-CF-.YYYY.-', 'Campaign': 'SAL-CAM-.YYYY.-', - 'Clinical Procedure': 'HLC-CPR-.YYYY.-', 'Course Schedule': 'EDU-CSH-.YYYY.-', 'Customer': 'CUST-.YYYY.-', 'Delivery Note': 'MAT-DN-.YYYY.-', @@ -27,12 +25,10 @@ doctype_series_map = { 'Fee Schedule': 'EDU-FSH-.YYYY.-', 'Fee Structure': 'EDU-FST-.YYYY.-', 'Fees': 'EDU-FEE-.YYYY.-', - 'Inpatient Record': 'HLC-INP-.YYYY.-', 'Installation Note': 'MAT-INS-.YYYY.-', 'Instructor': 'EDU-INS-.YYYY.-', 'Issue': 'ISS-.YYYY.-', 'Journal Entry': 'ACC-JV-.YYYY.-', - 'Lab Test': 'HLC-LT-.YYYY.-', 'Landed Cost Voucher': 'MAT-LCV-.YYYY.-', 'Lead': 'CRM-LEAD-.YYYY.-', 'Leave Allocation': 'HR-LAL-.YYYY.-', @@ -43,9 +39,6 @@ doctype_series_map = { 'Member': 'NPO-MEM-.YYYY.-', 'Opportunity': 'CRM-OPP-.YYYY.-', 'Packing Slip': 'MAT-PAC-.YYYY.-', - 'Patient': 'HLC-PAT-.YYYY.-', - 'Patient Encounter': 'HLC-ENC-.YYYY.-', - 'Patient Medical Record': 'HLC-PMR-.YYYY.-', 'Payment Entry': 'ACC-PAY-.YYYY.-', 'Payment Request': 'ACC-PRQ-.YYYY.-', 'Production Plan': 'MFG-PP-.YYYY.-', diff --git a/erpnext/patches/v11_0/remove_modules_setup_page.py b/erpnext/patches/v11_0/remove_modules_setup_page.py index eab3237878e..91f4bc5d0e2 100644 --- a/erpnext/patches/v11_0/remove_modules_setup_page.py +++ b/erpnext/patches/v11_0/remove_modules_setup_page.py @@ -1,7 +1,6 @@ # Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors # License: GNU General Public License v3. See license.txt -from __future__ import unicode_literals import frappe diff --git a/erpnext/patches/v11_0/rename_additional_salary_component_additional_salary.py b/erpnext/patches/v11_0/rename_additional_salary_component_additional_salary.py index 5b2c2863f2f..8fa876dd743 100644 --- a/erpnext/patches/v11_0/rename_additional_salary_component_additional_salary.py +++ b/erpnext/patches/v11_0/rename_additional_salary_component_additional_salary.py @@ -1,5 +1,3 @@ -from __future__ import unicode_literals - import frappe # this patch should have been included with this PR https://github.com/frappe/erpnext/pull/14302 diff --git a/erpnext/patches/v11_0/rename_asset_adjustment_doctype.py b/erpnext/patches/v11_0/rename_asset_adjustment_doctype.py index 707dff75e24..c7a3aa2abd4 100644 --- a/erpnext/patches/v11_0/rename_asset_adjustment_doctype.py +++ b/erpnext/patches/v11_0/rename_asset_adjustment_doctype.py @@ -1,7 +1,6 @@ # Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors # License: GNU General Public License v3. See license.txt -from __future__ import unicode_literals import frappe diff --git a/erpnext/patches/v11_0/rename_bom_wo_fields.py b/erpnext/patches/v11_0/rename_bom_wo_fields.py index 4ad6ea9999d..cab7d0a673f 100644 --- a/erpnext/patches/v11_0/rename_bom_wo_fields.py +++ b/erpnext/patches/v11_0/rename_bom_wo_fields.py @@ -1,7 +1,6 @@ # Copyright (c) 2018, Frappe and Contributors # License: GNU General Public License v3. See license.txt -from __future__ import unicode_literals import frappe from frappe.model.utils.rename_field import rename_field diff --git a/erpnext/patches/v11_0/rename_field_max_days_allowed.py b/erpnext/patches/v11_0/rename_field_max_days_allowed.py index 48f73fb2f41..4b55aa06bbf 100644 --- a/erpnext/patches/v11_0/rename_field_max_days_allowed.py +++ b/erpnext/patches/v11_0/rename_field_max_days_allowed.py @@ -1,5 +1,3 @@ -from __future__ import unicode_literals - import frappe from frappe.model.utils.rename_field import rename_field diff --git a/erpnext/patches/v11_0/rename_health_insurance.py b/erpnext/patches/v11_0/rename_health_insurance.py deleted file mode 100644 index a4f53b078e1..00000000000 --- a/erpnext/patches/v11_0/rename_health_insurance.py +++ /dev/null @@ -1,11 +0,0 @@ -# Copyright (c) 2018, Frappe and Contributors -# License: GNU General Public License v3. See license.txt - -from __future__ import unicode_literals - -import frappe - - -def execute(): - frappe.rename_doc('DocType', 'Health Insurance', 'Employee Health Insurance', force=True) - frappe.reload_doc('hr', 'doctype', 'employee_health_insurance') diff --git a/erpnext/patches/v11_0/rename_healthcare_doctype_and_fields.py b/erpnext/patches/v11_0/rename_healthcare_doctype_and_fields.py deleted file mode 100644 index 7a8c52f102f..00000000000 --- a/erpnext/patches/v11_0/rename_healthcare_doctype_and_fields.py +++ /dev/null @@ -1,67 +0,0 @@ -from __future__ import unicode_literals - -import frappe -from frappe.model.utils.rename_field import rename_field -from frappe.modules import get_doctype_module, scrub - -field_rename_map = { - "Patient Encounter": [ - ["consultation_time", "encounter_time"], - ["consultation_date", "encounter_date"], - ["consultation_comment", "encounter_comment"], - ["physician", "practitioner"] - ], - "Fee Validity": [ - ["physician", "practitioner"] - ], - "Lab Test": [ - ["physician", "practitioner"] - ], - "Patient Appointment": [ - ["physician", "practitioner"], - ["referring_physician", "referring_practitioner"] - ], - "Procedure Prescription": [ - ["physician", "practitioner"] - ] -} - -doc_rename_map = { - "Physician Schedule Time Slot": "Healthcare Schedule Time Slot", - "Physician Schedule": "Practitioner Schedule", - "Physician Service Unit Schedule": "Practitioner Service Unit Schedule", - "Consultation": "Patient Encounter", - "Physician": "Healthcare Practitioner" -} - -def execute(): - for dt in doc_rename_map: - if frappe.db.exists('DocType', dt): - frappe.rename_doc('DocType', dt, doc_rename_map[dt], force=True) - - for dn in field_rename_map: - if frappe.db.exists('DocType', dn): - frappe.reload_doc(get_doctype_module(dn), "doctype", scrub(dn)) - - for dt, field_list in field_rename_map.items(): - if frappe.db.exists('DocType', dt): - for field in field_list: - if frappe.db.has_column(dt, field[0]): - rename_field(dt, field[0], field[1]) - - if frappe.db.exists('DocType', 'Practitioner Service Unit Schedule'): - if frappe.db.has_column('Practitioner Service Unit Schedule', 'parentfield'): - frappe.db.sql(""" - update `tabPractitioner Service Unit Schedule` set parentfield = 'practitioner_schedules' - where parentfield = 'physician_schedules' and parenttype = 'Healthcare Practitioner' - """) - - if frappe.db.exists("DocType", "Healthcare Practitioner"): - frappe.reload_doc("healthcare", "doctype", "healthcare_practitioner") - frappe.reload_doc("healthcare", "doctype", "practitioner_service_unit_schedule") - if frappe.db.has_column('Healthcare Practitioner', 'physician_schedule'): - for doc in frappe.get_all('Healthcare Practitioner'): - _doc = frappe.get_doc('Healthcare Practitioner', doc.name) - if _doc.physician_schedule: - _doc.append('practitioner_schedules', {'schedule': _doc.physician_schedule}) - _doc.save() diff --git a/erpnext/patches/v11_0/rename_healthcare_fields.py b/erpnext/patches/v11_0/rename_healthcare_fields.py deleted file mode 100644 index 5c96367a737..00000000000 --- a/erpnext/patches/v11_0/rename_healthcare_fields.py +++ /dev/null @@ -1,54 +0,0 @@ -from __future__ import unicode_literals - -import frappe -from frappe.model.utils.rename_field import rename_field -from frappe.modules import get_doctype_module, scrub - -lab_test_name = ["test_name", "lab_test_name"] -lab_test_code = ["test_code", "lab_test_code"] -lab_test_comment = ["test_comment", "lab_test_comment"] -lab_test_created = ["test_created", "lab_test_created"] -lab_test_template = ["test_template", "lab_test_template"] -lab_test_rate = ["test_rate", "lab_test_rate"] -lab_test_description = ["test_description", "lab_test_description"] -lab_test_group = ["test_group", "lab_test_group"] -lab_test_template_type = ["test_template_type", "lab_test_template_type"] -lab_test_uom = ["test_uom", "lab_test_uom"] -lab_test_normal_range = ["test_normal_range", "lab_test_normal_range"] -lab_test_event = ["test_event", "lab_test_event"] -lab_test_particulars = ["test_particulars", "lab_test_particulars"] - -field_rename_map = { - "Lab Test Template": [lab_test_name, lab_test_code, lab_test_rate, lab_test_description, - lab_test_group, lab_test_template_type, lab_test_uom, lab_test_normal_range], - "Normal Test Items": [lab_test_name, lab_test_comment, lab_test_uom, lab_test_event], - "Lab Test": [lab_test_name, lab_test_comment, lab_test_group], - "Lab Prescription": [lab_test_name, lab_test_code, lab_test_comment, lab_test_created], - "Lab Test Groups": [lab_test_template, lab_test_rate, lab_test_description], - "Lab Test UOM": [lab_test_uom], - "Normal Test Template": [lab_test_uom, lab_test_event], - "Special Test Items": [lab_test_particulars] -} - - -def execute(): - for dt, field_list in field_rename_map.items(): - if frappe.db.exists('DocType', dt): - frappe.reload_doc(get_doctype_module(dt), "doctype", scrub(dt)) - for field in field_list: - if frappe.db.has_column(dt, field[0]): - rename_field(dt, field[0], field[1]) - - if frappe.db.exists('DocType', 'Lab Prescription'): - if frappe.db.has_column('Lab Prescription', 'parentfield'): - frappe.db.sql(""" - update `tabLab Prescription` set parentfield = 'lab_test_prescription' - where parentfield = 'test_prescription' - """) - - if frappe.db.exists('DocType', 'Lab Test Groups'): - if frappe.db.has_column('Lab Test Groups', 'parentfield'): - frappe.db.sql(""" - update `tabLab Test Groups` set parentfield = 'lab_test_groups' - where parentfield = 'test_groups' - """) diff --git a/erpnext/patches/v11_0/rename_members_with_naming_series.py b/erpnext/patches/v11_0/rename_members_with_naming_series.py index a3d7970aa1f..95fb55d9b45 100644 --- a/erpnext/patches/v11_0/rename_members_with_naming_series.py +++ b/erpnext/patches/v11_0/rename_members_with_naming_series.py @@ -1,5 +1,3 @@ -from __future__ import unicode_literals - import frappe diff --git a/erpnext/patches/v11_0/rename_overproduction_percent_field.py b/erpnext/patches/v11_0/rename_overproduction_percent_field.py index c7124af2e45..c78ec5d0128 100644 --- a/erpnext/patches/v11_0/rename_overproduction_percent_field.py +++ b/erpnext/patches/v11_0/rename_overproduction_percent_field.py @@ -1,7 +1,6 @@ # Copyright (c) 2018, Frappe and Contributors # License: GNU General Public License v3. See license.txt -from __future__ import unicode_literals import frappe from frappe.model.utils.rename_field import rename_field diff --git a/erpnext/patches/v11_0/rename_production_order_to_work_order.py b/erpnext/patches/v11_0/rename_production_order_to_work_order.py index 995f1affe4e..453a5710a1d 100644 --- a/erpnext/patches/v11_0/rename_production_order_to_work_order.py +++ b/erpnext/patches/v11_0/rename_production_order_to_work_order.py @@ -1,7 +1,6 @@ # Copyright (c) 2018, Frappe and Contributors # License: GNU General Public License v3. See license.txt -from __future__ import unicode_literals import frappe from frappe.model.utils.rename_field import rename_field diff --git a/erpnext/patches/v11_0/rename_supplier_type_to_supplier_group.py b/erpnext/patches/v11_0/rename_supplier_type_to_supplier_group.py index 2e53fb832fe..3f87550224d 100644 --- a/erpnext/patches/v11_0/rename_supplier_type_to_supplier_group.py +++ b/erpnext/patches/v11_0/rename_supplier_type_to_supplier_group.py @@ -1,5 +1,3 @@ -from __future__ import unicode_literals - import frappe from frappe import _ from frappe.model.utils.rename_field import rename_field diff --git a/erpnext/patches/v11_0/renamed_from_to_fields_in_project.py b/erpnext/patches/v11_0/renamed_from_to_fields_in_project.py index 894aaee5f0b..f23a81494be 100644 --- a/erpnext/patches/v11_0/renamed_from_to_fields_in_project.py +++ b/erpnext/patches/v11_0/renamed_from_to_fields_in_project.py @@ -1,7 +1,6 @@ # Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors # License: GNU General Public License v3. See license.txt -from __future__ import unicode_literals import frappe from frappe.model.utils.rename_field import rename_field diff --git a/erpnext/patches/v11_0/reset_publish_in_hub_for_all_items.py b/erpnext/patches/v11_0/reset_publish_in_hub_for_all_items.py deleted file mode 100644 index a664baf6dd6..00000000000 --- a/erpnext/patches/v11_0/reset_publish_in_hub_for_all_items.py +++ /dev/null @@ -1,8 +0,0 @@ -from __future__ import unicode_literals - -import frappe - - -def execute(): - frappe.reload_doc('stock', 'doctype', 'item') - frappe.db.sql("""update `tabItem` set publish_in_hub = 0""") diff --git a/erpnext/patches/v11_0/set_default_email_template_in_hr.py b/erpnext/patches/v11_0/set_default_email_template_in_hr.py index ff754247fba..ee083ca4b80 100644 --- a/erpnext/patches/v11_0/set_default_email_template_in_hr.py +++ b/erpnext/patches/v11_0/set_default_email_template_in_hr.py @@ -1,5 +1,3 @@ -from __future__ import unicode_literals - import frappe from frappe import _ diff --git a/erpnext/patches/v11_0/set_department_for_doctypes.py b/erpnext/patches/v11_0/set_department_for_doctypes.py index c9699655db3..b1098abb57a 100644 --- a/erpnext/patches/v11_0/set_department_for_doctypes.py +++ b/erpnext/patches/v11_0/set_department_for_doctypes.py @@ -1,5 +1,3 @@ -from __future__ import unicode_literals - import frappe # Set department value based on employee value diff --git a/erpnext/patches/v11_0/set_missing_gst_hsn_code.py b/erpnext/patches/v11_0/set_missing_gst_hsn_code.py index 7a0a9890252..ec75d454aa8 100644 --- a/erpnext/patches/v11_0/set_missing_gst_hsn_code.py +++ b/erpnext/patches/v11_0/set_missing_gst_hsn_code.py @@ -1,5 +1,3 @@ -from __future__ import unicode_literals - import frappe from erpnext.controllers.taxes_and_totals import get_itemised_tax_breakup_html diff --git a/erpnext/patches/v11_0/set_salary_component_properties.py b/erpnext/patches/v11_0/set_salary_component_properties.py index b70dc357aa7..99c3b0b7c46 100644 --- a/erpnext/patches/v11_0/set_salary_component_properties.py +++ b/erpnext/patches/v11_0/set_salary_component_properties.py @@ -1,5 +1,3 @@ -from __future__ import unicode_literals - import frappe diff --git a/erpnext/patches/v11_0/set_update_field_and_value_in_workflow_state.py b/erpnext/patches/v11_0/set_update_field_and_value_in_workflow_state.py index da4d4bd943a..a44daaa1979 100644 --- a/erpnext/patches/v11_0/set_update_field_and_value_in_workflow_state.py +++ b/erpnext/patches/v11_0/set_update_field_and_value_in_workflow_state.py @@ -1,5 +1,3 @@ -from __future__ import unicode_literals - import frappe from frappe.model.workflow import get_workflow_name diff --git a/erpnext/patches/v11_0/set_user_permissions_for_department.py b/erpnext/patches/v11_0/set_user_permissions_for_department.py index 7840d5e0feb..bb7ef877476 100644 --- a/erpnext/patches/v11_0/set_user_permissions_for_department.py +++ b/erpnext/patches/v11_0/set_user_permissions_for_department.py @@ -1,5 +1,3 @@ -from __future__ import unicode_literals - import frappe diff --git a/erpnext/patches/v11_0/skip_user_permission_check_for_department.py b/erpnext/patches/v11_0/skip_user_permission_check_for_department.py index 66d1b6b40ab..d3875773108 100644 --- a/erpnext/patches/v11_0/skip_user_permission_check_for_department.py +++ b/erpnext/patches/v11_0/skip_user_permission_check_for_department.py @@ -1,5 +1,3 @@ -from __future__ import unicode_literals - import frappe from frappe.desk.form.linked_with import get_linked_doctypes diff --git a/erpnext/patches/v11_0/uom_conversion_data.py b/erpnext/patches/v11_0/uom_conversion_data.py index a408d86b9a7..81e547b16a8 100644 --- a/erpnext/patches/v11_0/uom_conversion_data.py +++ b/erpnext/patches/v11_0/uom_conversion_data.py @@ -1,5 +1,3 @@ -from __future__ import unicode_literals - import frappe diff --git a/erpnext/patches/v11_0/update_account_type_in_party_type.py b/erpnext/patches/v11_0/update_account_type_in_party_type.py index e51874f48a0..c66cef042d9 100644 --- a/erpnext/patches/v11_0/update_account_type_in_party_type.py +++ b/erpnext/patches/v11_0/update_account_type_in_party_type.py @@ -1,7 +1,6 @@ # Copyright (c) 2017, Frappe and Contributors # License: GNU General Public License v3. See license.txt -from __future__ import unicode_literals import frappe diff --git a/erpnext/patches/v11_0/update_allow_transfer_for_manufacture.py b/erpnext/patches/v11_0/update_allow_transfer_for_manufacture.py index bfcfc9f6f44..3e36a4bb90d 100644 --- a/erpnext/patches/v11_0/update_allow_transfer_for_manufacture.py +++ b/erpnext/patches/v11_0/update_allow_transfer_for_manufacture.py @@ -1,7 +1,6 @@ # Copyright (c) 2018, Frappe and Contributors # License: GNU General Public License v3. See license.txt -from __future__ import unicode_literals import frappe diff --git a/erpnext/patches/v11_0/update_backflush_subcontract_rm_based_on_bom.py b/erpnext/patches/v11_0/update_backflush_subcontract_rm_based_on_bom.py index c3b18bd9817..f3a2ac6a655 100644 --- a/erpnext/patches/v11_0/update_backflush_subcontract_rm_based_on_bom.py +++ b/erpnext/patches/v11_0/update_backflush_subcontract_rm_based_on_bom.py @@ -1,7 +1,6 @@ # Copyright (c) 2017, Frappe and Contributors # License: GNU General Public License v3. See license.txt -from __future__ import unicode_literals import frappe diff --git a/erpnext/patches/v11_0/update_brand_in_item_price.py b/erpnext/patches/v11_0/update_brand_in_item_price.py index a489378895d..ce1df78083f 100644 --- a/erpnext/patches/v11_0/update_brand_in_item_price.py +++ b/erpnext/patches/v11_0/update_brand_in_item_price.py @@ -1,7 +1,6 @@ # Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors # License: GNU General Public License v3. See license.txt -from __future__ import unicode_literals import frappe diff --git a/erpnext/patches/v11_0/update_delivery_trip_status.py b/erpnext/patches/v11_0/update_delivery_trip_status.py index da259582747..35b95353b12 100755 --- a/erpnext/patches/v11_0/update_delivery_trip_status.py +++ b/erpnext/patches/v11_0/update_delivery_trip_status.py @@ -1,7 +1,6 @@ # Copyright (c) 2017, Frappe and Contributors # License: GNU General Public License v3. See license.txt -from __future__ import unicode_literals import frappe diff --git a/erpnext/patches/v11_0/update_department_lft_rgt.py b/erpnext/patches/v11_0/update_department_lft_rgt.py index f7ecf6e4523..aff8e1556b9 100644 --- a/erpnext/patches/v11_0/update_department_lft_rgt.py +++ b/erpnext/patches/v11_0/update_department_lft_rgt.py @@ -1,5 +1,3 @@ -from __future__ import unicode_literals - import frappe from frappe import _ from frappe.utils.nestedset import rebuild_tree diff --git a/erpnext/patches/v11_0/update_hub_url.py b/erpnext/patches/v11_0/update_hub_url.py deleted file mode 100644 index c89b9b50607..00000000000 --- a/erpnext/patches/v11_0/update_hub_url.py +++ /dev/null @@ -1,8 +0,0 @@ -from __future__ import unicode_literals - -import frappe - - -def execute(): - frappe.reload_doc('hub_node', 'doctype', 'Marketplace Settings') - frappe.db.set_value('Marketplace Settings', 'Marketplace Settings', 'marketplace_url', 'https://hubmarket.org') diff --git a/erpnext/patches/v11_0/update_sales_partner_type.py b/erpnext/patches/v11_0/update_sales_partner_type.py index 1369805349d..ef58499f0f1 100644 --- a/erpnext/patches/v11_0/update_sales_partner_type.py +++ b/erpnext/patches/v11_0/update_sales_partner_type.py @@ -1,5 +1,3 @@ -from __future__ import unicode_literals - import frappe from frappe import _ diff --git a/erpnext/patches/v11_0/update_total_qty_field.py b/erpnext/patches/v11_0/update_total_qty_field.py index e79a5f9e6bc..4e807b4f136 100644 --- a/erpnext/patches/v11_0/update_total_qty_field.py +++ b/erpnext/patches/v11_0/update_total_qty_field.py @@ -1,5 +1,3 @@ -from __future__ import unicode_literals - import frappe diff --git a/erpnext/patches/v11_1/delete_bom_browser.py b/erpnext/patches/v11_1/delete_bom_browser.py index aad3df267c8..9b5c169717a 100644 --- a/erpnext/patches/v11_1/delete_bom_browser.py +++ b/erpnext/patches/v11_1/delete_bom_browser.py @@ -1,7 +1,6 @@ # Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors # License: GNU General Public License v3. See license.txt -from __future__ import unicode_literals import frappe diff --git a/erpnext/patches/v11_1/delete_scheduling_tool.py b/erpnext/patches/v11_1/delete_scheduling_tool.py index 56d0dbf1a1f..6f3da92ee74 100644 --- a/erpnext/patches/v11_1/delete_scheduling_tool.py +++ b/erpnext/patches/v11_1/delete_scheduling_tool.py @@ -1,7 +1,6 @@ # Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors # License: GNU General Public License v3. See license.txt -from __future__ import unicode_literals import frappe diff --git a/erpnext/patches/v11_1/make_job_card_time_logs.py b/erpnext/patches/v11_1/make_job_card_time_logs.py index db0c3454c74..100cd64f8fe 100644 --- a/erpnext/patches/v11_1/make_job_card_time_logs.py +++ b/erpnext/patches/v11_1/make_job_card_time_logs.py @@ -1,7 +1,6 @@ # Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors # License: GNU General Public License v3. See license.txt -from __future__ import unicode_literals import frappe diff --git a/erpnext/patches/v11_1/move_customer_lead_to_dynamic_column.py b/erpnext/patches/v11_1/move_customer_lead_to_dynamic_column.py index 9ea6cd82c9c..d292d7ae432 100644 --- a/erpnext/patches/v11_1/move_customer_lead_to_dynamic_column.py +++ b/erpnext/patches/v11_1/move_customer_lead_to_dynamic_column.py @@ -1,7 +1,6 @@ # Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors # License: GNU General Public License v3. See license.txt -from __future__ import unicode_literals import frappe diff --git a/erpnext/patches/v11_1/rename_depends_on_lwp.py b/erpnext/patches/v11_1/rename_depends_on_lwp.py index 95a8225832c..4e71838aa06 100644 --- a/erpnext/patches/v11_1/rename_depends_on_lwp.py +++ b/erpnext/patches/v11_1/rename_depends_on_lwp.py @@ -1,7 +1,6 @@ # Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors # License: GNU General Public License v3. See license.txt -from __future__ import unicode_literals import frappe from frappe import scrub diff --git a/erpnext/patches/v11_1/renamed_delayed_item_report.py b/erpnext/patches/v11_1/renamed_delayed_item_report.py index 21285637c4e..c160b79d0e9 100644 --- a/erpnext/patches/v11_1/renamed_delayed_item_report.py +++ b/erpnext/patches/v11_1/renamed_delayed_item_report.py @@ -1,7 +1,6 @@ # Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors # License: GNU General Public License v3. See license.txt -from __future__ import unicode_literals import frappe diff --git a/erpnext/patches/v11_1/set_default_action_for_quality_inspection.py b/erpnext/patches/v11_1/set_default_action_for_quality_inspection.py index 4325490c793..672b7628bb4 100644 --- a/erpnext/patches/v11_1/set_default_action_for_quality_inspection.py +++ b/erpnext/patches/v11_1/set_default_action_for_quality_inspection.py @@ -1,7 +1,6 @@ # Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors # License: GNU General Public License v3. See license.txt -from __future__ import unicode_literals import frappe diff --git a/erpnext/patches/v11_1/set_missing_opportunity_from.py b/erpnext/patches/v11_1/set_missing_opportunity_from.py index 6569200a14c..beec63af4b4 100644 --- a/erpnext/patches/v11_1/set_missing_opportunity_from.py +++ b/erpnext/patches/v11_1/set_missing_opportunity_from.py @@ -1,5 +1,3 @@ -from __future__ import unicode_literals - import frappe diff --git a/erpnext/patches/v11_1/set_salary_details_submittable.py b/erpnext/patches/v11_1/set_salary_details_submittable.py index 4a4cf302575..ac082b1ae22 100644 --- a/erpnext/patches/v11_1/set_salary_details_submittable.py +++ b/erpnext/patches/v11_1/set_salary_details_submittable.py @@ -1,5 +1,3 @@ -from __future__ import unicode_literals - import frappe diff --git a/erpnext/patches/v11_1/set_status_for_material_request_type_manufacture.py b/erpnext/patches/v11_1/set_status_for_material_request_type_manufacture.py index 64db97e92bc..0d4f3d2ce11 100644 --- a/erpnext/patches/v11_1/set_status_for_material_request_type_manufacture.py +++ b/erpnext/patches/v11_1/set_status_for_material_request_type_manufacture.py @@ -1,5 +1,3 @@ -from __future__ import unicode_literals - import frappe diff --git a/erpnext/patches/v11_1/set_variant_based_on.py b/erpnext/patches/v11_1/set_variant_based_on.py index b69767d7ea4..2e06e63a8aa 100644 --- a/erpnext/patches/v11_1/set_variant_based_on.py +++ b/erpnext/patches/v11_1/set_variant_based_on.py @@ -1,7 +1,6 @@ # Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors # License: GNU General Public License v3. See license.txt -from __future__ import unicode_literals import frappe diff --git a/erpnext/patches/v11_1/setup_guardian_role.py b/erpnext/patches/v11_1/setup_guardian_role.py index bb33f19e9cf..dd9c1d28871 100644 --- a/erpnext/patches/v11_1/setup_guardian_role.py +++ b/erpnext/patches/v11_1/setup_guardian_role.py @@ -1,5 +1,3 @@ -from __future__ import unicode_literals - import frappe diff --git a/erpnext/patches/v11_1/update_bank_transaction_status.py b/erpnext/patches/v11_1/update_bank_transaction_status.py index 33007afcd8c..9b8be3de1b0 100644 --- a/erpnext/patches/v11_1/update_bank_transaction_status.py +++ b/erpnext/patches/v11_1/update_bank_transaction_status.py @@ -1,7 +1,6 @@ # Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors # License: GNU General Public License v3. See license.txt -from __future__ import unicode_literals import frappe diff --git a/erpnext/patches/v11_1/update_default_supplier_in_item_defaults.py b/erpnext/patches/v11_1/update_default_supplier_in_item_defaults.py index 22dabae7d2e..902df201a42 100644 --- a/erpnext/patches/v11_1/update_default_supplier_in_item_defaults.py +++ b/erpnext/patches/v11_1/update_default_supplier_in_item_defaults.py @@ -1,7 +1,6 @@ # Copyright (c) 2018, Frappe and Contributors # License: GNU General Public License v3. See license.txt -from __future__ import unicode_literals import frappe diff --git a/erpnext/patches/v11_1/woocommerce_set_creation_user.py b/erpnext/patches/v11_1/woocommerce_set_creation_user.py index e7218b1ade5..19958eef14a 100644 --- a/erpnext/patches/v11_1/woocommerce_set_creation_user.py +++ b/erpnext/patches/v11_1/woocommerce_set_creation_user.py @@ -1,5 +1,3 @@ -from __future__ import unicode_literals - import frappe from frappe.utils import cint diff --git a/erpnext/patches/v12_0/add_default_buying_selling_terms_in_company.py b/erpnext/patches/v12_0/add_default_buying_selling_terms_in_company.py index 384a1f5022a..80187d834a4 100644 --- a/erpnext/patches/v12_0/add_default_buying_selling_terms_in_company.py +++ b/erpnext/patches/v12_0/add_default_buying_selling_terms_in_company.py @@ -1,7 +1,6 @@ # Copyright (c) 2019, Frappe and Contributors # License: GNU General Public License v3. See license.txt -from __future__ import unicode_literals import frappe from frappe.model.utils.rename_field import rename_field diff --git a/erpnext/patches/v12_0/add_document_type_field_for_italy_einvoicing.py b/erpnext/patches/v12_0/add_document_type_field_for_italy_einvoicing.py index 7f39dfef59d..f860cb46935 100644 --- a/erpnext/patches/v12_0/add_document_type_field_for_italy_einvoicing.py +++ b/erpnext/patches/v12_0/add_document_type_field_for_italy_einvoicing.py @@ -1,5 +1,3 @@ -from __future__ import unicode_literals - import frappe from frappe.custom.doctype.custom_field.custom_field import create_custom_fields diff --git a/erpnext/patches/v12_0/add_export_type_field_in_party_master.py b/erpnext/patches/v12_0/add_export_type_field_in_party_master.py index e05c8211c03..dc9e8849189 100644 --- a/erpnext/patches/v12_0/add_export_type_field_in_party_master.py +++ b/erpnext/patches/v12_0/add_export_type_field_in_party_master.py @@ -1,5 +1,3 @@ -from __future__ import unicode_literals - import frappe from erpnext.regional.india.setup import make_custom_fields diff --git a/erpnext/patches/v12_0/add_gst_category_in_delivery_note.py b/erpnext/patches/v12_0/add_gst_category_in_delivery_note.py index 30e47cb333c..6316bb3da94 100644 --- a/erpnext/patches/v12_0/add_gst_category_in_delivery_note.py +++ b/erpnext/patches/v12_0/add_gst_category_in_delivery_note.py @@ -1,5 +1,3 @@ -from __future__ import unicode_literals - import frappe from frappe.custom.doctype.custom_field.custom_field import create_custom_fields diff --git a/erpnext/patches/v12_0/add_taxjar_integration_field.py b/erpnext/patches/v12_0/add_taxjar_integration_field.py index d10a6d79f29..b0ddf001a65 100644 --- a/erpnext/patches/v12_0/add_taxjar_integration_field.py +++ b/erpnext/patches/v12_0/add_taxjar_integration_field.py @@ -1,5 +1,3 @@ -from __future__ import unicode_literals - import frappe from erpnext.regional.united_states.setup import make_custom_fields diff --git a/erpnext/patches/v12_0/create_accounting_dimensions_in_missing_doctypes.py b/erpnext/patches/v12_0/create_accounting_dimensions_in_missing_doctypes.py index 02fbe62837a..aec9cb8b26b 100644 --- a/erpnext/patches/v12_0/create_accounting_dimensions_in_missing_doctypes.py +++ b/erpnext/patches/v12_0/create_accounting_dimensions_in_missing_doctypes.py @@ -1,5 +1,3 @@ -from __future__ import unicode_literals - import frappe from frappe.custom.doctype.custom_field.custom_field import create_custom_field diff --git a/erpnext/patches/v12_0/create_irs_1099_field_united_states.py b/erpnext/patches/v12_0/create_irs_1099_field_united_states.py index 65265c4c8e8..efcc7cf0f7d 100644 --- a/erpnext/patches/v12_0/create_irs_1099_field_united_states.py +++ b/erpnext/patches/v12_0/create_irs_1099_field_united_states.py @@ -1,5 +1,3 @@ -from __future__ import unicode_literals - import frappe from erpnext.regional.united_states.setup import make_custom_fields diff --git a/erpnext/patches/v12_0/create_itc_reversal_custom_fields.py b/erpnext/patches/v12_0/create_itc_reversal_custom_fields.py index 9267ebffb27..d157aad8f2d 100644 --- a/erpnext/patches/v12_0/create_itc_reversal_custom_fields.py +++ b/erpnext/patches/v12_0/create_itc_reversal_custom_fields.py @@ -1,5 +1,3 @@ -from __future__ import unicode_literals - import frappe from frappe.custom.doctype.custom_field.custom_field import create_custom_fields from frappe.custom.doctype.property_setter.property_setter import make_property_setter diff --git a/erpnext/patches/v12_0/create_taxable_value_field.py b/erpnext/patches/v12_0/create_taxable_value_field.py index 40de8d8aef2..55717ccab2e 100644 --- a/erpnext/patches/v12_0/create_taxable_value_field.py +++ b/erpnext/patches/v12_0/create_taxable_value_field.py @@ -1,5 +1,3 @@ -from __future__ import unicode_literals - import frappe from frappe.custom.doctype.custom_field.custom_field import create_custom_fields diff --git a/erpnext/patches/v12_0/generate_leave_ledger_entries.py b/erpnext/patches/v12_0/generate_leave_ledger_entries.py index aed56d621b8..90e46d07e40 100644 --- a/erpnext/patches/v12_0/generate_leave_ledger_entries.py +++ b/erpnext/patches/v12_0/generate_leave_ledger_entries.py @@ -1,7 +1,6 @@ # Copyright (c) 2018, Frappe and Contributors # License: GNU General Public License v3. See license.txt -from __future__ import unicode_literals import frappe from frappe.utils import getdate, today diff --git a/erpnext/patches/v12_0/make_item_manufacturer.py b/erpnext/patches/v12_0/make_item_manufacturer.py index cfc2472e9e2..d66f429de3c 100644 --- a/erpnext/patches/v12_0/make_item_manufacturer.py +++ b/erpnext/patches/v12_0/make_item_manufacturer.py @@ -1,7 +1,6 @@ # Copyright (c) 2017, Frappe and Contributors # License: GNU General Public License v3. See license.txt -from __future__ import unicode_literals import frappe diff --git a/erpnext/patches/v12_0/move_bank_account_swift_number_to_bank.py b/erpnext/patches/v12_0/move_bank_account_swift_number_to_bank.py index 3e9d429ed18..b3ee3404642 100644 --- a/erpnext/patches/v12_0/move_bank_account_swift_number_to_bank.py +++ b/erpnext/patches/v12_0/move_bank_account_swift_number_to_bank.py @@ -1,5 +1,3 @@ -from __future__ import unicode_literals - import frappe diff --git a/erpnext/patches/v12_0/move_credit_limit_to_customer_credit_limit.py b/erpnext/patches/v12_0/move_credit_limit_to_customer_credit_limit.py index 2662632b52b..82dfba52c9f 100644 --- a/erpnext/patches/v12_0/move_credit_limit_to_customer_credit_limit.py +++ b/erpnext/patches/v12_0/move_credit_limit_to_customer_credit_limit.py @@ -1,7 +1,6 @@ # Copyright (c) 2019, Frappe and Contributors # License: GNU General Public License v3. See license.txt -from __future__ import unicode_literals import frappe diff --git a/erpnext/patches/v12_0/move_due_advance_amount_to_pending_amount.py b/erpnext/patches/v12_0/move_due_advance_amount_to_pending_amount.py index 55f5cd52a35..5de7e69620b 100644 --- a/erpnext/patches/v12_0/move_due_advance_amount_to_pending_amount.py +++ b/erpnext/patches/v12_0/move_due_advance_amount_to_pending_amount.py @@ -1,7 +1,6 @@ # Copyright (c) 2019, Frappe and Contributors # License: GNU General Public License v3. See license.txt -from __future__ import unicode_literals import frappe diff --git a/erpnext/patches/v12_0/move_item_tax_to_item_tax_template.py b/erpnext/patches/v12_0/move_item_tax_to_item_tax_template.py index 677a564af0d..905aebee151 100644 --- a/erpnext/patches/v12_0/move_item_tax_to_item_tax_template.py +++ b/erpnext/patches/v12_0/move_item_tax_to_item_tax_template.py @@ -2,7 +2,6 @@ import json import frappe from frappe.model.naming import make_autoname -from six import iteritems def execute(): @@ -84,7 +83,7 @@ def execute(): def get_item_tax_template(item_tax_templates, item_tax_map, item_code, parenttype=None, parent=None, tax_types=None): # search for previously created item tax template by comparing tax maps - for template, item_tax_template_map in iteritems(item_tax_templates): + for template, item_tax_template_map in item_tax_templates.items(): if item_tax_map == item_tax_template_map: return template @@ -92,7 +91,7 @@ def get_item_tax_template(item_tax_templates, item_tax_map, item_code, parenttyp item_tax_template = frappe.new_doc("Item Tax Template") item_tax_template.title = make_autoname("Item Tax Template-.####") - for tax_type, tax_rate in iteritems(item_tax_map): + for tax_type, tax_rate in item_tax_map.items(): account_details = frappe.db.get_value("Account", tax_type, ['name', 'account_type', 'company'], as_dict=1) if account_details: item_tax_template.company = account_details.company diff --git a/erpnext/patches/v12_0/move_plaid_settings_to_doctype.py b/erpnext/patches/v12_0/move_plaid_settings_to_doctype.py index dafea280c28..c396891b59e 100644 --- a/erpnext/patches/v12_0/move_plaid_settings_to_doctype.py +++ b/erpnext/patches/v12_0/move_plaid_settings_to_doctype.py @@ -1,7 +1,6 @@ # Copyright (c) 2017, Frappe and Contributors # License: GNU General Public License v3. See license.txt -from __future__ import unicode_literals import frappe diff --git a/erpnext/patches/v12_0/move_target_distribution_from_parent_to_child.py b/erpnext/patches/v12_0/move_target_distribution_from_parent_to_child.py index 72f4df5cabc..1e230a787c2 100644 --- a/erpnext/patches/v12_0/move_target_distribution_from_parent_to_child.py +++ b/erpnext/patches/v12_0/move_target_distribution_from_parent_to_child.py @@ -1,7 +1,6 @@ # Copyright (c) 2017, Frappe and Contributors # License: GNU General Public License v3. See license.txt -from __future__ import unicode_literals import frappe diff --git a/erpnext/patches/v12_0/recalculate_requested_qty_in_bin.py b/erpnext/patches/v12_0/recalculate_requested_qty_in_bin.py index a19e9a96dba..9b083cafb3a 100644 --- a/erpnext/patches/v12_0/recalculate_requested_qty_in_bin.py +++ b/erpnext/patches/v12_0/recalculate_requested_qty_in_bin.py @@ -1,5 +1,3 @@ -from __future__ import unicode_literals - import frappe from erpnext.stock.stock_balance import get_indented_qty, update_bin_qty diff --git a/erpnext/patches/v12_0/remove_bank_remittance_custom_fields.py b/erpnext/patches/v12_0/remove_bank_remittance_custom_fields.py index fba41184159..12768a6f959 100644 --- a/erpnext/patches/v12_0/remove_bank_remittance_custom_fields.py +++ b/erpnext/patches/v12_0/remove_bank_remittance_custom_fields.py @@ -1,5 +1,3 @@ -from __future__ import unicode_literals - import frappe diff --git a/erpnext/patches/v12_0/remove_denied_leaves_from_leave_ledger.py b/erpnext/patches/v12_0/remove_denied_leaves_from_leave_ledger.py index f6a1984e17a..d1d4bcc140f 100644 --- a/erpnext/patches/v12_0/remove_denied_leaves_from_leave_ledger.py +++ b/erpnext/patches/v12_0/remove_denied_leaves_from_leave_ledger.py @@ -1,7 +1,6 @@ # Copyright (c) 2018, Frappe and Contributors # License: GNU General Public License v3. See license.txt -from __future__ import unicode_literals import frappe diff --git a/erpnext/patches/v12_0/remove_duplicate_leave_ledger_entries.py b/erpnext/patches/v12_0/remove_duplicate_leave_ledger_entries.py index 6fa1c04dad3..6ad68ccc6e4 100644 --- a/erpnext/patches/v12_0/remove_duplicate_leave_ledger_entries.py +++ b/erpnext/patches/v12_0/remove_duplicate_leave_ledger_entries.py @@ -1,7 +1,6 @@ # Copyright (c) 2018, Frappe and Contributors # License: GNU General Public License v3. See license.txt -from __future__ import unicode_literals import frappe diff --git a/erpnext/patches/v12_0/remove_patient_medical_record_page.py b/erpnext/patches/v12_0/remove_patient_medical_record_page.py index bf71c4810ff..e02bf62dfbc 100644 --- a/erpnext/patches/v12_0/remove_patient_medical_record_page.py +++ b/erpnext/patches/v12_0/remove_patient_medical_record_page.py @@ -1,6 +1,5 @@ # Copyright (c) 2019 -from __future__ import unicode_literals import frappe diff --git a/erpnext/patches/v12_0/rename_account_type_doctype.py b/erpnext/patches/v12_0/rename_account_type_doctype.py index 27357a8ef15..e33a1d010d1 100644 --- a/erpnext/patches/v12_0/rename_account_type_doctype.py +++ b/erpnext/patches/v12_0/rename_account_type_doctype.py @@ -1,5 +1,3 @@ -from __future__ import unicode_literals - import frappe diff --git a/erpnext/patches/v12_0/rename_bank_account_field_in_journal_entry_account.py b/erpnext/patches/v12_0/rename_bank_account_field_in_journal_entry_account.py index 7e02fff4d82..a5d986a0a16 100644 --- a/erpnext/patches/v12_0/rename_bank_account_field_in_journal_entry_account.py +++ b/erpnext/patches/v12_0/rename_bank_account_field_in_journal_entry_account.py @@ -1,7 +1,6 @@ # Copyright (c) 2019, Frappe and Contributors # License: GNU General Public License v3. See license.txt -from __future__ import unicode_literals import frappe from frappe.model.utils.rename_field import rename_field diff --git a/erpnext/patches/v12_0/rename_bank_reconciliation.py b/erpnext/patches/v12_0/rename_bank_reconciliation.py index 5c79ce2a81b..51ff0c8c949 100644 --- a/erpnext/patches/v12_0/rename_bank_reconciliation.py +++ b/erpnext/patches/v12_0/rename_bank_reconciliation.py @@ -1,7 +1,6 @@ # Copyright (c) 2018, Frappe and Contributors # License: GNU General Public License v3. See license.txt -from __future__ import unicode_literals import frappe diff --git a/erpnext/patches/v12_0/rename_lost_reason_detail.py b/erpnext/patches/v12_0/rename_lost_reason_detail.py index 337302a3c18..96ae9798c65 100644 --- a/erpnext/patches/v12_0/rename_lost_reason_detail.py +++ b/erpnext/patches/v12_0/rename_lost_reason_detail.py @@ -1,5 +1,3 @@ -from __future__ import unicode_literals - import frappe diff --git a/erpnext/patches/v12_0/rename_pos_closing_doctype.py b/erpnext/patches/v12_0/rename_pos_closing_doctype.py index e6fb1f31e16..f5f0112e036 100644 --- a/erpnext/patches/v12_0/rename_pos_closing_doctype.py +++ b/erpnext/patches/v12_0/rename_pos_closing_doctype.py @@ -1,6 +1,5 @@ # License: GNU General Public License v3. See license.txt -from __future__ import unicode_literals import frappe diff --git a/erpnext/patches/v12_0/rename_pricing_rule_child_doctypes.py b/erpnext/patches/v12_0/rename_pricing_rule_child_doctypes.py index 4bf3840b783..87630fbcaf9 100644 --- a/erpnext/patches/v12_0/rename_pricing_rule_child_doctypes.py +++ b/erpnext/patches/v12_0/rename_pricing_rule_child_doctypes.py @@ -1,7 +1,6 @@ # Copyright (c) 2017, Frappe and Contributors # License: GNU General Public License v3. See license.txt -from __future__ import unicode_literals import frappe diff --git a/erpnext/patches/v12_0/repost_stock_ledger_entries_for_target_warehouse.py b/erpnext/patches/v12_0/repost_stock_ledger_entries_for_target_warehouse.py index 5150430dbb9..198963df711 100644 --- a/erpnext/patches/v12_0/repost_stock_ledger_entries_for_target_warehouse.py +++ b/erpnext/patches/v12_0/repost_stock_ledger_entries_for_target_warehouse.py @@ -1,7 +1,6 @@ # Copyright (c) 2020, Frappe and Contributors # License: GNU General Public License v3. See license.txt -from __future__ import unicode_literals import frappe diff --git a/erpnext/patches/v12_0/set_automatically_process_deferred_accounting_in_accounts_settings.py b/erpnext/patches/v12_0/set_automatically_process_deferred_accounting_in_accounts_settings.py index 849e96e9665..8f29fc888e0 100644 --- a/erpnext/patches/v12_0/set_automatically_process_deferred_accounting_in_accounts_settings.py +++ b/erpnext/patches/v12_0/set_automatically_process_deferred_accounting_in_accounts_settings.py @@ -1,5 +1,3 @@ -from __future__ import unicode_literals - import frappe diff --git a/erpnext/patches/v12_0/set_cwip_and_delete_asset_settings.py b/erpnext/patches/v12_0/set_cwip_and_delete_asset_settings.py index e363c26a86f..d1e0e4550eb 100644 --- a/erpnext/patches/v12_0/set_cwip_and_delete_asset_settings.py +++ b/erpnext/patches/v12_0/set_cwip_and_delete_asset_settings.py @@ -1,5 +1,3 @@ -from __future__ import unicode_literals - import frappe from frappe.utils import cint diff --git a/erpnext/patches/v12_0/set_default_payroll_based_on.py b/erpnext/patches/v12_0/set_default_payroll_based_on.py index 85112f2a540..de641c65a1c 100644 --- a/erpnext/patches/v12_0/set_default_payroll_based_on.py +++ b/erpnext/patches/v12_0/set_default_payroll_based_on.py @@ -1,5 +1,3 @@ -from __future__ import unicode_literals - import frappe diff --git a/erpnext/patches/v12_0/set_expense_account_in_landed_cost_voucher_taxes.py b/erpnext/patches/v12_0/set_expense_account_in_landed_cost_voucher_taxes.py index 49b3bff0f82..50d9fee0992 100644 --- a/erpnext/patches/v12_0/set_expense_account_in_landed_cost_voucher_taxes.py +++ b/erpnext/patches/v12_0/set_expense_account_in_landed_cost_voucher_taxes.py @@ -1,7 +1,4 @@ -from __future__ import unicode_literals - import frappe -from six import iteritems def execute(): @@ -11,7 +8,7 @@ def execute(): SELECT name, expenses_included_in_valuation from `tabCompany` """)) - for company, account in iteritems(company_account_map): + for company, account in company_account_map.items(): frappe.db.sql(""" UPDATE `tabLanded Cost Taxes and Charges` t, `tabLanded Cost Voucher` l diff --git a/erpnext/patches/v12_0/set_italian_import_supplier_invoice_permissions.py b/erpnext/patches/v12_0/set_italian_import_supplier_invoice_permissions.py index a991b3c15df..b942fa4365f 100644 --- a/erpnext/patches/v12_0/set_italian_import_supplier_invoice_permissions.py +++ b/erpnext/patches/v12_0/set_italian_import_supplier_invoice_permissions.py @@ -1,7 +1,6 @@ # Copyright (c) 2017, Frappe and Contributors # License: GNU General Public License v3. See license.txt -from __future__ import unicode_literals import frappe diff --git a/erpnext/patches/v12_0/set_multi_uom_in_rfq.py b/erpnext/patches/v12_0/set_multi_uom_in_rfq.py index fada5f08fb0..a8e0ec1f816 100644 --- a/erpnext/patches/v12_0/set_multi_uom_in_rfq.py +++ b/erpnext/patches/v12_0/set_multi_uom_in_rfq.py @@ -1,7 +1,6 @@ # Copyright (c) 2017, Frappe and Contributors # License: GNU General Public License v3. See license.txt -from __future__ import unicode_literals import frappe diff --git a/erpnext/patches/v12_0/set_production_capacity_in_workstation.py b/erpnext/patches/v12_0/set_production_capacity_in_workstation.py index 248d33504e1..bd2f7e2decd 100644 --- a/erpnext/patches/v12_0/set_production_capacity_in_workstation.py +++ b/erpnext/patches/v12_0/set_production_capacity_in_workstation.py @@ -1,5 +1,3 @@ -from __future__ import unicode_literals - import frappe diff --git a/erpnext/patches/v12_0/set_published_in_hub_tracked_item.py b/erpnext/patches/v12_0/set_published_in_hub_tracked_item.py deleted file mode 100644 index 73c6ce8220e..00000000000 --- a/erpnext/patches/v12_0/set_published_in_hub_tracked_item.py +++ /dev/null @@ -1,14 +0,0 @@ -from __future__ import unicode_literals - -import frappe - - -def execute(): - frappe.reload_doc("Hub Node", "doctype", "Hub Tracked Item") - if not frappe.db.a_row_exists("Hub Tracked Item"): - return - - frappe.db.sql(''' - Update `tabHub Tracked Item` - SET published = 1 - ''') diff --git a/erpnext/patches/v12_0/set_purchase_receipt_delivery_note_detail.py b/erpnext/patches/v12_0/set_purchase_receipt_delivery_note_detail.py index cad947fadcd..a15166ed5f6 100644 --- a/erpnext/patches/v12_0/set_purchase_receipt_delivery_note_detail.py +++ b/erpnext/patches/v12_0/set_purchase_receipt_delivery_note_detail.py @@ -1,5 +1,3 @@ -from __future__ import unicode_literals - from collections import defaultdict import frappe diff --git a/erpnext/patches/v12_0/set_quotation_status.py b/erpnext/patches/v12_0/set_quotation_status.py index bb172769ebb..91e77e4e0d4 100644 --- a/erpnext/patches/v12_0/set_quotation_status.py +++ b/erpnext/patches/v12_0/set_quotation_status.py @@ -1,5 +1,3 @@ -from __future__ import unicode_literals - import frappe diff --git a/erpnext/patches/v12_0/set_received_qty_in_material_request_as_per_stock_uom.py b/erpnext/patches/v12_0/set_received_qty_in_material_request_as_per_stock_uom.py index f8b510e3c37..d41134d4db3 100644 --- a/erpnext/patches/v12_0/set_received_qty_in_material_request_as_per_stock_uom.py +++ b/erpnext/patches/v12_0/set_received_qty_in_material_request_as_per_stock_uom.py @@ -1,5 +1,3 @@ -from __future__ import unicode_literals - import frappe diff --git a/erpnext/patches/v12_0/set_serial_no_status.py b/erpnext/patches/v12_0/set_serial_no_status.py index 9a05e707a65..8c136e66632 100644 --- a/erpnext/patches/v12_0/set_serial_no_status.py +++ b/erpnext/patches/v12_0/set_serial_no_status.py @@ -1,5 +1,3 @@ -from __future__ import unicode_literals - import frappe from frappe.utils import getdate, nowdate diff --git a/erpnext/patches/v12_0/set_updated_purpose_in_pick_list.py b/erpnext/patches/v12_0/set_updated_purpose_in_pick_list.py index 21ee23b2072..300d0f2ba47 100644 --- a/erpnext/patches/v12_0/set_updated_purpose_in_pick_list.py +++ b/erpnext/patches/v12_0/set_updated_purpose_in_pick_list.py @@ -1,7 +1,6 @@ # Copyright (c) 2019, Frappe and Contributors # License: GNU General Public License v3. See license.txt -from __future__ import unicode_literals import frappe diff --git a/erpnext/patches/v12_0/set_valid_till_date_in_supplier_quotation.py b/erpnext/patches/v12_0/set_valid_till_date_in_supplier_quotation.py index 72d5521f44d..154d7ba1767 100644 --- a/erpnext/patches/v12_0/set_valid_till_date_in_supplier_quotation.py +++ b/erpnext/patches/v12_0/set_valid_till_date_in_supplier_quotation.py @@ -1,5 +1,3 @@ -from __future__ import unicode_literals - import frappe diff --git a/erpnext/patches/v12_0/stock_entry_enhancements.py b/erpnext/patches/v12_0/stock_entry_enhancements.py index b99501d942d..94d8ff9cde3 100644 --- a/erpnext/patches/v12_0/stock_entry_enhancements.py +++ b/erpnext/patches/v12_0/stock_entry_enhancements.py @@ -2,7 +2,6 @@ # License: GNU General Public License v3. See license.txt -from __future__ import unicode_literals import frappe from frappe.custom.doctype.custom_field.custom_field import create_custom_fields diff --git a/erpnext/patches/v12_0/unhide_cost_center_field.py b/erpnext/patches/v12_0/unhide_cost_center_field.py index 823dd226372..72450212872 100644 --- a/erpnext/patches/v12_0/unhide_cost_center_field.py +++ b/erpnext/patches/v12_0/unhide_cost_center_field.py @@ -1,7 +1,6 @@ # Copyright (c) 2017, Frappe and Contributors # License: GNU General Public License v3. See license.txt -from __future__ import unicode_literals import frappe diff --git a/erpnext/patches/v12_0/unset_customer_supplier_based_on_type_of_item_price.py b/erpnext/patches/v12_0/unset_customer_supplier_based_on_type_of_item_price.py index 61c4c601b55..5b5f623b48c 100644 --- a/erpnext/patches/v12_0/unset_customer_supplier_based_on_type_of_item_price.py +++ b/erpnext/patches/v12_0/unset_customer_supplier_based_on_type_of_item_price.py @@ -1,5 +1,3 @@ -from __future__ import unicode_literals - import frappe diff --git a/erpnext/patches/v12_0/update_address_template_for_india.py b/erpnext/patches/v12_0/update_address_template_for_india.py index d41aae2a876..64a2e41587f 100644 --- a/erpnext/patches/v12_0/update_address_template_for_india.py +++ b/erpnext/patches/v12_0/update_address_template_for_india.py @@ -1,7 +1,6 @@ # Copyright (c) 2020, Frappe and Contributors # License: GNU General Public License v3. See license.txt -from __future__ import unicode_literals import frappe diff --git a/erpnext/patches/v12_0/update_appointment_reminder_scheduler_entry.py b/erpnext/patches/v12_0/update_appointment_reminder_scheduler_entry.py deleted file mode 100644 index 024cb2b7630..00000000000 --- a/erpnext/patches/v12_0/update_appointment_reminder_scheduler_entry.py +++ /dev/null @@ -1,8 +0,0 @@ -import frappe - - -def execute(): - job = frappe.db.exists('Scheduled Job Type', 'patient_appointment.send_appointment_reminder') - if job: - method = 'erpnext.healthcare.doctype.patient_appointment.patient_appointment.send_appointment_reminder' - frappe.db.set_value('Scheduled Job Type', job, 'method', method) diff --git a/erpnext/patches/v12_0/update_bom_in_so_mr.py b/erpnext/patches/v12_0/update_bom_in_so_mr.py index 283407567f2..37d850fab44 100644 --- a/erpnext/patches/v12_0/update_bom_in_so_mr.py +++ b/erpnext/patches/v12_0/update_bom_in_so_mr.py @@ -1,5 +1,3 @@ -from __future__ import unicode_literals - import frappe diff --git a/erpnext/patches/v12_0/update_due_date_in_gle.py b/erpnext/patches/v12_0/update_due_date_in_gle.py index 60ad3251146..e4418b01036 100644 --- a/erpnext/patches/v12_0/update_due_date_in_gle.py +++ b/erpnext/patches/v12_0/update_due_date_in_gle.py @@ -1,5 +1,3 @@ -from __future__ import unicode_literals - import frappe diff --git a/erpnext/patches/v12_0/update_end_date_and_status_in_email_campaign.py b/erpnext/patches/v12_0/update_end_date_and_status_in_email_campaign.py index 208076b1496..ef4204fc9c3 100644 --- a/erpnext/patches/v12_0/update_end_date_and_status_in_email_campaign.py +++ b/erpnext/patches/v12_0/update_end_date_and_status_in_email_campaign.py @@ -1,5 +1,3 @@ -from __future__ import unicode_literals - import frappe from frappe.utils import add_days, getdate, today diff --git a/erpnext/patches/v12_0/update_ewaybill_field_position.py b/erpnext/patches/v12_0/update_ewaybill_field_position.py index 520b5d04b4b..132fd900bd1 100644 --- a/erpnext/patches/v12_0/update_ewaybill_field_position.py +++ b/erpnext/patches/v12_0/update_ewaybill_field_position.py @@ -1,5 +1,3 @@ -from __future__ import unicode_literals - import frappe diff --git a/erpnext/patches/v12_0/update_gst_category.py b/erpnext/patches/v12_0/update_gst_category.py index bee89199316..8b15370b09d 100644 --- a/erpnext/patches/v12_0/update_gst_category.py +++ b/erpnext/patches/v12_0/update_gst_category.py @@ -1,5 +1,3 @@ -from __future__ import unicode_literals - import frappe diff --git a/erpnext/patches/v12_0/update_healthcare_refactored_changes.py b/erpnext/patches/v12_0/update_healthcare_refactored_changes.py index bfad3ddcba7..f553ee9d855 100644 --- a/erpnext/patches/v12_0/update_healthcare_refactored_changes.py +++ b/erpnext/patches/v12_0/update_healthcare_refactored_changes.py @@ -1,5 +1,3 @@ -from __future__ import unicode_literals - import frappe from frappe.model.utils.rename_field import rename_field from frappe.modules import get_doctype_module, scrub diff --git a/erpnext/patches/v12_0/update_is_cancelled_field.py b/erpnext/patches/v12_0/update_is_cancelled_field.py index 3e7c37f0d19..df7875079bc 100644 --- a/erpnext/patches/v12_0/update_is_cancelled_field.py +++ b/erpnext/patches/v12_0/update_is_cancelled_field.py @@ -1,5 +1,3 @@ -from __future__ import unicode_literals - import frappe diff --git a/erpnext/patches/v12_0/update_item_tax_template_company.py b/erpnext/patches/v12_0/update_item_tax_template_company.py index 3ad983d686f..abd4f6fb180 100644 --- a/erpnext/patches/v12_0/update_item_tax_template_company.py +++ b/erpnext/patches/v12_0/update_item_tax_template_company.py @@ -1,5 +1,3 @@ -from __future__ import unicode_literals - import frappe diff --git a/erpnext/patches/v12_0/update_owner_fields_in_acc_dimension_custom_fields.py b/erpnext/patches/v12_0/update_owner_fields_in_acc_dimension_custom_fields.py index 09e2319eb80..e5f24d4b888 100644 --- a/erpnext/patches/v12_0/update_owner_fields_in_acc_dimension_custom_fields.py +++ b/erpnext/patches/v12_0/update_owner_fields_in_acc_dimension_custom_fields.py @@ -1,5 +1,3 @@ -from __future__ import unicode_literals - import frappe from erpnext.accounts.doctype.accounting_dimension.accounting_dimension import ( diff --git a/erpnext/patches/v12_0/update_price_list_currency_in_bom.py b/erpnext/patches/v12_0/update_price_list_currency_in_bom.py index e4c10089235..ea3e002e5d2 100644 --- a/erpnext/patches/v12_0/update_price_list_currency_in_bom.py +++ b/erpnext/patches/v12_0/update_price_list_currency_in_bom.py @@ -1,5 +1,3 @@ -from __future__ import unicode_literals - import frappe from frappe.utils import getdate diff --git a/erpnext/patches/v12_0/update_price_or_product_discount.py b/erpnext/patches/v12_0/update_price_or_product_discount.py index 4ff39257688..53c0ba525b2 100644 --- a/erpnext/patches/v12_0/update_price_or_product_discount.py +++ b/erpnext/patches/v12_0/update_price_or_product_discount.py @@ -1,5 +1,3 @@ -from __future__ import unicode_literals - import frappe diff --git a/erpnext/patches/v12_0/update_pricing_rule_fields.py b/erpnext/patches/v12_0/update_pricing_rule_fields.py index 6f102e9b42b..b7c36ae7780 100644 --- a/erpnext/patches/v12_0/update_pricing_rule_fields.py +++ b/erpnext/patches/v12_0/update_pricing_rule_fields.py @@ -1,7 +1,6 @@ # Copyright (c) 2017, Frappe and Contributors # License: GNU General Public License v3. See license.txt -from __future__ import unicode_literals import frappe diff --git a/erpnext/patches/v12_0/update_production_plan_status.py b/erpnext/patches/v12_0/update_production_plan_status.py new file mode 100644 index 00000000000..06fc503a33f --- /dev/null +++ b/erpnext/patches/v12_0/update_production_plan_status.py @@ -0,0 +1,31 @@ +# Copyright (c) 2021, Frappe and Contributors +# License: GNU General Public License v3. See license.txt + +import frappe + + +def execute(): + frappe.reload_doc("manufacturing", "doctype", "production_plan") + frappe.db.sql(""" + UPDATE `tabProduction Plan` ppl + SET status = "Completed" + WHERE ppl.name IN ( + SELECT ss.name FROM ( + SELECT + ( + count(wo.status = "Completed") = + count(pp.name) + ) = + ( + pp.status != "Completed" + AND pp.total_produced_qty >= pp.total_planned_qty + ) AS should_set, + pp.name AS name + FROM + `tabWork Order` wo INNER JOIN`tabProduction Plan` pp + ON wo.production_plan = pp.name + GROUP BY pp.name + HAVING should_set = 1 + ) ss + ) + """) diff --git a/erpnext/patches/v12_0/update_uom_conversion_factor.py b/erpnext/patches/v12_0/update_uom_conversion_factor.py index 7c7477a6739..a09ac190e2e 100644 --- a/erpnext/patches/v12_0/update_uom_conversion_factor.py +++ b/erpnext/patches/v12_0/update_uom_conversion_factor.py @@ -1,5 +1,3 @@ -from __future__ import unicode_literals - import frappe diff --git a/erpnext/patches/v13_0/add_custom_field_for_south_africa.py b/erpnext/patches/v13_0/add_custom_field_for_south_africa.py index 96aa5477f01..b34b5c1801f 100644 --- a/erpnext/patches/v13_0/add_custom_field_for_south_africa.py +++ b/erpnext/patches/v13_0/add_custom_field_for_south_africa.py @@ -12,6 +12,7 @@ def execute(): return frappe.reload_doc('regional', 'doctype', 'south_africa_vat_settings') + frappe.reload_doc('regional', 'report', 'vat_audit_report') frappe.reload_doc('accounts', 'doctype', 'south_africa_vat_account') make_custom_fields() diff --git a/erpnext/patches/v13_0/add_default_interview_notification_templates.py b/erpnext/patches/v13_0/add_default_interview_notification_templates.py new file mode 100644 index 00000000000..0208ca914eb --- /dev/null +++ b/erpnext/patches/v13_0/add_default_interview_notification_templates.py @@ -0,0 +1,35 @@ +import os + +import frappe +from frappe import _ + + +def execute(): + if not frappe.db.exists('Email Template', _('Interview Reminder')): + base_path = frappe.get_app_path('erpnext', 'hr', 'doctype') + response = frappe.read_file(os.path.join(base_path, 'interview/interview_reminder_notification_template.html')) + + frappe.get_doc({ + 'doctype': 'Email Template', + 'name': _('Interview Reminder'), + 'response': response, + 'subject': _('Interview Reminder'), + 'owner': frappe.session.user, + }).insert(ignore_permissions=True) + + if not frappe.db.exists('Email Template', _('Interview Feedback Reminder')): + base_path = frappe.get_app_path('erpnext', 'hr', 'doctype') + response = frappe.read_file(os.path.join(base_path, 'interview/interview_feedback_reminder_template.html')) + + frappe.get_doc({ + 'doctype': 'Email Template', + 'name': _('Interview Feedback Reminder'), + 'response': response, + 'subject': _('Interview Feedback Reminder'), + 'owner': frappe.session.user, + }).insert(ignore_permissions=True) + + hr_settings = frappe.get_doc('HR Settings') + hr_settings.interview_reminder_template = _('Interview Reminder') + hr_settings.feedback_reminder_notification_template = _('Interview Feedback Reminder') + hr_settings.save() diff --git a/erpnext/patches/v13_0/add_doctype_to_sla.py b/erpnext/patches/v13_0/add_doctype_to_sla.py index 7252b3e8a87..8cee378d900 100644 --- a/erpnext/patches/v13_0/add_doctype_to_sla.py +++ b/erpnext/patches/v13_0/add_doctype_to_sla.py @@ -1,7 +1,6 @@ # Copyright (c) 2020, Frappe and Contributors # License: GNU General Public License v3. See license.txt -from __future__ import unicode_literals import frappe from frappe.model.utils.rename_field import rename_field diff --git a/erpnext/patches/v13_0/add_naming_series_to_old_projects.py b/erpnext/patches/v13_0/add_naming_series_to_old_projects.py index f029f75accd..71abe2e98e0 100644 --- a/erpnext/patches/v13_0/add_naming_series_to_old_projects.py +++ b/erpnext/patches/v13_0/add_naming_series_to_old_projects.py @@ -1,5 +1,3 @@ -from __future__ import unicode_literals - import frappe diff --git a/erpnext/patches/v13_0/add_po_to_global_search.py b/erpnext/patches/v13_0/add_po_to_global_search.py index 15b7c71dc2c..7fbaffb23c7 100644 --- a/erpnext/patches/v13_0/add_po_to_global_search.py +++ b/erpnext/patches/v13_0/add_po_to_global_search.py @@ -1,5 +1,3 @@ -from __future__ import unicode_literals - import frappe diff --git a/erpnext/patches/v13_0/add_standard_navbar_items.py b/erpnext/patches/v13_0/add_standard_navbar_items.py index 699c480c872..24141b7862d 100644 --- a/erpnext/patches/v13_0/add_standard_navbar_items.py +++ b/erpnext/patches/v13_0/add_standard_navbar_items.py @@ -1,5 +1,3 @@ -from __future__ import unicode_literals - # import frappe from erpnext.setup.install import add_standard_navbar_items diff --git a/erpnext/patches/v13_0/bill_for_rejected_quantity_in_purchase_invoice.py b/erpnext/patches/v13_0/bill_for_rejected_quantity_in_purchase_invoice.py index 07d1cee64f8..ee23747cc04 100644 --- a/erpnext/patches/v13_0/bill_for_rejected_quantity_in_purchase_invoice.py +++ b/erpnext/patches/v13_0/bill_for_rejected_quantity_in_purchase_invoice.py @@ -1,5 +1,3 @@ -from __future__ import unicode_literals - import frappe diff --git a/erpnext/patches/v13_0/change_default_pos_print_format.py b/erpnext/patches/v13_0/change_default_pos_print_format.py index 5a0320a7eb2..23cad31f596 100644 --- a/erpnext/patches/v13_0/change_default_pos_print_format.py +++ b/erpnext/patches/v13_0/change_default_pos_print_format.py @@ -1,5 +1,3 @@ -from __future__ import unicode_literals - import frappe diff --git a/erpnext/patches/v13_0/check_is_income_tax_component.py b/erpnext/patches/v13_0/check_is_income_tax_component.py index aac87ba36fa..b3ef5af1007 100644 --- a/erpnext/patches/v13_0/check_is_income_tax_component.py +++ b/erpnext/patches/v13_0/check_is_income_tax_component.py @@ -1,7 +1,6 @@ # Copyright (c) 2019, Frappe and Contributors # License: GNU General Public License v3. See license.txt -from __future__ import unicode_literals import frappe diff --git a/erpnext/patches/v13_0/convert_qi_parameter_to_link_field.py b/erpnext/patches/v13_0/convert_qi_parameter_to_link_field.py index 66ac62fdc4c..bc64c637722 100644 --- a/erpnext/patches/v13_0/convert_qi_parameter_to_link_field.py +++ b/erpnext/patches/v13_0/convert_qi_parameter_to_link_field.py @@ -1,5 +1,3 @@ -from __future__ import unicode_literals - import frappe diff --git a/erpnext/patches/v13_0/create_accounting_dimensions_in_pos_doctypes.py b/erpnext/patches/v13_0/create_accounting_dimensions_in_pos_doctypes.py new file mode 100644 index 00000000000..44501088102 --- /dev/null +++ b/erpnext/patches/v13_0/create_accounting_dimensions_in_pos_doctypes.py @@ -0,0 +1,42 @@ +import frappe +from frappe.custom.doctype.custom_field.custom_field import create_custom_field + + +def execute(): + frappe.reload_doc('accounts', 'doctype', 'accounting_dimension') + accounting_dimensions = frappe.db.sql("""select fieldname, label, document_type, disabled from + `tabAccounting Dimension`""", as_dict=1) + + if not accounting_dimensions: + return + + count = 1 + for d in accounting_dimensions: + + if count % 2 == 0: + insert_after_field = 'dimension_col_break' + else: + insert_after_field = 'accounting_dimensions_section' + + for doctype in ["POS Invoice", "POS Invoice Item"]: + + field = frappe.db.get_value("Custom Field", {"dt": doctype, "fieldname": d.fieldname}) + + if field: + continue + meta = frappe.get_meta(doctype, cached=False) + fieldnames = [d.fieldname for d in meta.get("fields")] + + df = { + "fieldname": d.fieldname, + "label": d.label, + "fieldtype": "Link", + "options": d.document_type, + "insert_after": insert_after_field + } + + if df['fieldname'] not in fieldnames: + create_custom_field(doctype, df) + frappe.clear_cache(doctype=doctype) + + count += 1 diff --git a/erpnext/patches/v13_0/create_custom_field_for_finance_book.py b/erpnext/patches/v13_0/create_custom_field_for_finance_book.py new file mode 100644 index 00000000000..313b0e9a2eb --- /dev/null +++ b/erpnext/patches/v13_0/create_custom_field_for_finance_book.py @@ -0,0 +1,21 @@ +import frappe +from frappe.custom.doctype.custom_field.custom_field import create_custom_fields + + +def execute(): + company = frappe.get_all('Company', filters = {'country': 'India'}) + if not company: + return + + custom_field = { + 'Finance Book': [ + { + 'fieldname': 'for_income_tax', + 'label': 'For Income Tax', + 'fieldtype': 'Check', + 'insert_after': 'finance_book_name', + 'description': 'If the asset is put to use for less than 180 days, the first Depreciation Rate will be reduced by 50%.' + } + ] + } + create_custom_fields(custom_field, update=1) diff --git a/erpnext/patches/v13_0/create_gst_payment_entry_fields.py b/erpnext/patches/v13_0/create_gst_payment_entry_fields.py index 334c9d2b816..7e6d67ce931 100644 --- a/erpnext/patches/v13_0/create_gst_payment_entry_fields.py +++ b/erpnext/patches/v13_0/create_gst_payment_entry_fields.py @@ -4,6 +4,7 @@ import frappe from frappe.custom.doctype.custom_field.custom_field import create_custom_fields + def execute(): frappe.reload_doc('accounts', 'doctype', 'advance_taxes_and_charges') frappe.reload_doc('accounts', 'doctype', 'payment_entry') diff --git a/erpnext/patches/v13_0/create_healthcare_custom_fields_in_stock_entry_detail.py b/erpnext/patches/v13_0/create_healthcare_custom_fields_in_stock_entry_detail.py deleted file mode 100644 index 543faeb74ac..00000000000 --- a/erpnext/patches/v13_0/create_healthcare_custom_fields_in_stock_entry_detail.py +++ /dev/null @@ -1,12 +0,0 @@ -import frappe -from frappe.custom.doctype.custom_field.custom_field import create_custom_fields - -from erpnext.domains.healthcare import data - - -def execute(): - if 'Healthcare' not in frappe.get_active_domains(): - return - - if data['custom_fields']: - create_custom_fields(data['custom_fields']) diff --git a/erpnext/patches/v13_0/create_ksa_vat_custom_fields.py b/erpnext/patches/v13_0/create_ksa_vat_custom_fields.py new file mode 100644 index 00000000000..f33b4b3ea0d --- /dev/null +++ b/erpnext/patches/v13_0/create_ksa_vat_custom_fields.py @@ -0,0 +1,12 @@ +import frappe + +from erpnext.regional.saudi_arabia.setup import make_custom_fields + + +def execute(): + company = frappe.get_all('Company', filters = {'country': 'Saudi Arabia'}) + if not company: + return + + make_custom_fields() + diff --git a/erpnext/patches/v13_0/create_leave_policy_assignment_based_on_employee_current_leave_policy.py b/erpnext/patches/v13_0/create_leave_policy_assignment_based_on_employee_current_leave_policy.py index b1b5c24adc8..55125431b52 100644 --- a/erpnext/patches/v13_0/create_leave_policy_assignment_based_on_employee_current_leave_policy.py +++ b/erpnext/patches/v13_0/create_leave_policy_assignment_based_on_employee_current_leave_policy.py @@ -1,7 +1,6 @@ # Copyright (c) 2019, Frappe and Contributors # License: GNU General Public License v3. See license.txt -from __future__ import unicode_literals import frappe diff --git a/erpnext/patches/v13_0/create_pan_field_for_india.py b/erpnext/patches/v13_0/create_pan_field_for_india.py new file mode 100644 index 00000000000..6df6e1eb329 --- /dev/null +++ b/erpnext/patches/v13_0/create_pan_field_for_india.py @@ -0,0 +1,29 @@ +import frappe +from frappe.custom.doctype.custom_field.custom_field import create_custom_fields + + +def execute(): + frappe.reload_doc('buying', 'doctype', 'supplier', force=True) + frappe.reload_doc('selling', 'doctype', 'customer', force=True) + frappe.reload_doc('core', 'doctype', 'doctype', force=True) + + custom_fields = { + 'Supplier': [ + { + 'fieldname': 'pan', + 'label': 'PAN', + 'fieldtype': 'Data', + 'insert_after': 'supplier_type' + } + ], + 'Customer': [ + { + 'fieldname': 'pan', + 'label': 'PAN', + 'fieldtype': 'Data', + 'insert_after': 'customer_type' + } + ] + } + + create_custom_fields(custom_fields, update=True) diff --git a/erpnext/patches/v13_0/create_uae_pos_invoice_fields.py b/erpnext/patches/v13_0/create_uae_pos_invoice_fields.py index 3bfa78fa282..87c9cf1ebd5 100644 --- a/erpnext/patches/v13_0/create_uae_pos_invoice_fields.py +++ b/erpnext/patches/v13_0/create_uae_pos_invoice_fields.py @@ -1,7 +1,6 @@ # Copyright (c) 2019, Frappe and Contributors # License: GNU General Public License v3. See license.txt -from __future__ import unicode_literals import frappe diff --git a/erpnext/patches/v13_0/custom_fields_for_taxjar_integration.py b/erpnext/patches/v13_0/custom_fields_for_taxjar_integration.py index eee9f1189e5..078c558d885 100644 --- a/erpnext/patches/v13_0/custom_fields_for_taxjar_integration.py +++ b/erpnext/patches/v13_0/custom_fields_for_taxjar_integration.py @@ -1,9 +1,7 @@ -from __future__ import unicode_literals - import frappe from frappe.custom.doctype.custom_field.custom_field import create_custom_fields -from erpnext.regional.united_states.setup import add_permissions +from erpnext.erpnext_integrations.doctype.taxjar_settings.taxjar_settings import add_permissions def execute(): @@ -11,22 +9,31 @@ def execute(): if not company: return - frappe.reload_doc("regional", "doctype", "product_tax_category") + TAXJAR_CREATE_TRANSACTIONS = frappe.db.get_single_value("TaxJar Settings", "taxjar_create_transactions") + TAXJAR_CALCULATE_TAX = frappe.db.get_single_value("TaxJar Settings", "taxjar_calculate_tax") + TAXJAR_SANDBOX_MODE = frappe.db.get_single_value("TaxJar Settings", "is_sandbox") + + if (not TAXJAR_CREATE_TRANSACTIONS and not TAXJAR_CALCULATE_TAX and not TAXJAR_SANDBOX_MODE): + return custom_fields = { 'Sales Invoice Item': [ dict(fieldname='product_tax_category', fieldtype='Link', insert_after='description', options='Product Tax Category', label='Product Tax Category', fetch_from='item_code.product_tax_category'), dict(fieldname='tax_collectable', fieldtype='Currency', insert_after='net_amount', - label='Tax Collectable', read_only=1), + label='Tax Collectable', read_only=1, options='currency'), dict(fieldname='taxable_amount', fieldtype='Currency', insert_after='tax_collectable', - label='Taxable Amount', read_only=1) + label='Taxable Amount', read_only=1, options='currency') ], 'Item': [ dict(fieldname='product_tax_category', fieldtype='Link', insert_after='item_group', options='Product Tax Category', label='Product Tax Category') + ], + 'TaxJar Settings': [ + dict(fieldname='company', fieldtype='Link', insert_after='configuration', options='Company', + label='Company') ] } create_custom_fields(custom_fields, update=True) add_permissions() - frappe.enqueue('erpnext.regional.united_states.setup.add_product_tax_categories', now=True) + frappe.enqueue('erpnext.erpnext_integrations.doctype.taxjar_settings.taxjar_settings.add_product_tax_categories', now=True) diff --git a/erpnext/patches/v13_0/delete_old_bank_reconciliation_doctypes.py b/erpnext/patches/v13_0/delete_old_bank_reconciliation_doctypes.py index 089bbe3b48f..2c5c577978e 100644 --- a/erpnext/patches/v13_0/delete_old_bank_reconciliation_doctypes.py +++ b/erpnext/patches/v13_0/delete_old_bank_reconciliation_doctypes.py @@ -1,7 +1,6 @@ # Copyright (c) 2019, Frappe and Contributors # License: GNU General Public License v3. See license.txt -from __future__ import unicode_literals import frappe from frappe.model.utils.rename_field import rename_field diff --git a/erpnext/patches/v13_0/delete_old_purchase_reports.py b/erpnext/patches/v13_0/delete_old_purchase_reports.py index 3cb7e120d67..e57d6d0d3e2 100644 --- a/erpnext/patches/v13_0/delete_old_purchase_reports.py +++ b/erpnext/patches/v13_0/delete_old_purchase_reports.py @@ -1,7 +1,6 @@ # Copyright (c) 2019, Frappe and Contributors # License: GNU General Public License v3. See license.txt -from __future__ import unicode_literals import frappe diff --git a/erpnext/patches/v13_0/delete_old_sales_reports.py b/erpnext/patches/v13_0/delete_old_sales_reports.py index c9a366655ce..c597fe86457 100644 --- a/erpnext/patches/v13_0/delete_old_sales_reports.py +++ b/erpnext/patches/v13_0/delete_old_sales_reports.py @@ -1,7 +1,6 @@ # Copyright (c) 2019, Frappe and Contributors # License: GNU General Public License v3. See license.txt -from __future__ import unicode_literals import frappe diff --git a/erpnext/patches/v13_0/delete_orphaned_tables.py b/erpnext/patches/v13_0/delete_orphaned_tables.py index 1ea22d63561..c32f83067bc 100644 --- a/erpnext/patches/v13_0/delete_orphaned_tables.py +++ b/erpnext/patches/v13_0/delete_orphaned_tables.py @@ -1,7 +1,6 @@ # Copyright (c) 2019, Frappe and Contributors # License: GNU General Public License v3. See license.txt -from __future__ import unicode_literals import frappe from frappe.utils import getdate diff --git a/erpnext/patches/v13_0/drop_razorpay_payload_column.py b/erpnext/patches/v13_0/drop_razorpay_payload_column.py index a7aee521983..611ba7e3243 100644 --- a/erpnext/patches/v13_0/drop_razorpay_payload_column.py +++ b/erpnext/patches/v13_0/drop_razorpay_payload_column.py @@ -1,5 +1,3 @@ -from __future__ import unicode_literals - import frappe diff --git a/erpnext/patches/v13_0/enable_scheduler_job_for_item_reposting.py b/erpnext/patches/v13_0/enable_scheduler_job_for_item_reposting.py new file mode 100644 index 00000000000..7a51b432117 --- /dev/null +++ b/erpnext/patches/v13_0/enable_scheduler_job_for_item_reposting.py @@ -0,0 +1,8 @@ +import frappe + + +def execute(): + frappe.reload_doc('core', 'doctype', 'scheduled_job_type') + if frappe.db.exists('Scheduled Job Type', 'repost_item_valuation.repost_entries'): + frappe.db.set_value('Scheduled Job Type', + 'repost_item_valuation.repost_entries', 'stopped', 0) diff --git a/erpnext/patches/v13_0/fix_additional_cost_in_mfg_stock_entry.py b/erpnext/patches/v13_0/fix_additional_cost_in_mfg_stock_entry.py new file mode 100644 index 00000000000..aeb8d8eb588 --- /dev/null +++ b/erpnext/patches/v13_0/fix_additional_cost_in_mfg_stock_entry.py @@ -0,0 +1,76 @@ +from typing import List, NewType + +import frappe + +StockEntryCode = NewType("StockEntryCode", str) + + +def execute(): + stock_entry_codes = find_broken_stock_entries() + + for stock_entry_code in stock_entry_codes: + patched_stock_entry = patch_additional_cost(stock_entry_code) + create_repost_item_valuation(patched_stock_entry) + + +def find_broken_stock_entries() -> List[StockEntryCode]: + period_closing_date = frappe.db.get_value( + "Period Closing Voucher", {"docstatus": 1}, "posting_date", order_by="posting_date desc" + ) + + stock_entries_to_patch = frappe.db.sql( + """ + select se.name, sum(sed.additional_cost) as item_additional_cost, se.total_additional_costs + from `tabStock Entry` se + join `tabStock Entry Detail` sed + on sed.parent = se.name + where + se.docstatus = 1 and + se.posting_date > %s + group by + sed.parent + having + item_additional_cost != se.total_additional_costs + """, + period_closing_date, + as_dict=True, + ) + + return [d.name for d in stock_entries_to_patch] + + +def patch_additional_cost(code: StockEntryCode): + stock_entry = frappe.get_doc("Stock Entry", code) + stock_entry.distribute_additional_costs() + stock_entry.update_valuation_rate() + stock_entry.set_total_incoming_outgoing_value() + stock_entry.set_total_amount() + stock_entry.db_update() + for item in stock_entry.items: + item.db_update() + return stock_entry + + +def create_repost_item_valuation(stock_entry): + from erpnext.controllers.stock_controller import create_repost_item_valuation_entry + + # turn on recalculate flag so reposting corrects the incoming/outgoing rates. + frappe.db.set_value( + "Stock Ledger Entry", + {"voucher_no": stock_entry.name, "actual_qty": (">", 0)}, + "recalculate_rate", + 1, + update_modified=False, + ) + + create_repost_item_valuation_entry( + args=frappe._dict( + { + "posting_date": stock_entry.posting_date, + "posting_time": stock_entry.posting_time, + "voucher_type": stock_entry.doctype, + "voucher_no": stock_entry.name, + "company": stock_entry.company, + } + ) + ) diff --git a/erpnext/patches/v13_0/fix_invoice_statuses.py b/erpnext/patches/v13_0/fix_invoice_statuses.py new file mode 100644 index 00000000000..4395757159f --- /dev/null +++ b/erpnext/patches/v13_0/fix_invoice_statuses.py @@ -0,0 +1,113 @@ +import frappe +from frappe.utils import flt, getdate + +from erpnext.accounts.doctype.sales_invoice.sales_invoice import ( + get_total_in_party_account_currency, + is_overdue, +) + +TODAY = getdate() + +def execute(): + # This fix is not related to Party Specific Item, + # but it is needed for code introduced after Party Specific Item was + # If your DB doesn't have this doctype yet, you should be fine + if not frappe.db.exists("DocType", "Party Specific Item"): + return + + for doctype in ("Purchase Invoice", "Sales Invoice"): + fields = [ + "name", + "status", + "due_date", + "outstanding_amount", + "grand_total", + "base_grand_total", + "rounded_total", + "base_rounded_total", + "disable_rounded_total", + ] + if doctype == "Sales Invoice": + fields.append("is_pos") + + invoices_to_update = frappe.get_all( + doctype, + fields=fields, + filters={ + "docstatus": 1, + "status": ("in", ( + "Overdue", + "Overdue and Discounted", + "Partly Paid", + "Partly Paid and Discounted" + )), + "outstanding_amount": (">", 0), + "modified": (">", "2021-01-01") + # an assumption is being made that only invoices modified + # after 2021 got affected as incorrectly overdue. + # required for performance reasons. + } + ) + + invoices_to_update = { + invoice.name: invoice for invoice in invoices_to_update + } + + payment_schedule_items = frappe.get_all( + "Payment Schedule", + fields=( + "due_date", + "payment_amount", + "base_payment_amount", + "parent" + ), + filters={"parent": ("in", invoices_to_update)} + ) + + for item in payment_schedule_items: + invoices_to_update[item.parent].setdefault( + "payment_schedule", [] + ).append(item) + + status_map = {} + + for invoice in invoices_to_update.values(): + invoice.doctype = doctype + doc = frappe.get_doc(invoice) + correct_status = get_correct_status(doc) + if not correct_status or doc.status == correct_status: + continue + + status_map.setdefault(correct_status, []).append(doc.name) + + for status, docs in status_map.items(): + frappe.db.set_value( + doctype, {"name": ("in", docs)}, + "status", + status, + update_modified=False + ) + + + +def get_correct_status(doc): + outstanding_amount = flt( + doc.outstanding_amount, doc.precision("outstanding_amount") + ) + total = get_total_in_party_account_currency(doc) + + status = "" + if is_overdue(doc, total): + status = "Overdue" + elif 0 < outstanding_amount < total: + status = "Partly Paid" + elif outstanding_amount > 0 and getdate(doc.due_date) >= TODAY: + status = "Unpaid" + + if not status: + return + + if doc.status.endswith(" and Discounted"): + status += " and Discounted" + + return status diff --git a/erpnext/patches/v13_0/germany_fill_debtor_creditor_number.py b/erpnext/patches/v13_0/germany_fill_debtor_creditor_number.py index dca43b4193d..72cda751e6c 100644 --- a/erpnext/patches/v13_0/germany_fill_debtor_creditor_number.py +++ b/erpnext/patches/v13_0/germany_fill_debtor_creditor_number.py @@ -1,7 +1,6 @@ # Copyright (c) 2019, Frappe and Contributors # License: GNU General Public License v3. See license.txt -from __future__ import unicode_literals import frappe diff --git a/erpnext/patches/v13_0/germany_make_custom_fields.py b/erpnext/patches/v13_0/germany_make_custom_fields.py index 86ad1885990..80b6a3954a6 100644 --- a/erpnext/patches/v13_0/germany_make_custom_fields.py +++ b/erpnext/patches/v13_0/germany_make_custom_fields.py @@ -1,7 +1,6 @@ # Copyright (c) 2019, Frappe and Contributors # License: GNU General Public License v3. See license.txt -from __future__ import unicode_literals import frappe diff --git a/erpnext/patches/v13_0/gst_fields_for_pos_invoice.py b/erpnext/patches/v13_0/gst_fields_for_pos_invoice.py new file mode 100644 index 00000000000..76f8b274999 --- /dev/null +++ b/erpnext/patches/v13_0/gst_fields_for_pos_invoice.py @@ -0,0 +1,42 @@ +import frappe +from frappe.custom.doctype.custom_field.custom_field import create_custom_fields + + +def execute(): + company = frappe.get_all('Company', filters = {'country': 'India'}, fields=['name']) + if not company: + return + + hsn_sac_field = dict(fieldname='gst_hsn_code', label='HSN/SAC', + fieldtype='Data', fetch_from='item_code.gst_hsn_code', insert_after='description', + allow_on_submit=1, print_hide=1, fetch_if_empty=1) + nil_rated_exempt = dict(fieldname='is_nil_exempt', label='Is Nil Rated or Exempted', + fieldtype='Check', fetch_from='item_code.is_nil_exempt', insert_after='gst_hsn_code', + print_hide=1) + is_non_gst = dict(fieldname='is_non_gst', label='Is Non GST', + fieldtype='Check', fetch_from='item_code.is_non_gst', insert_after='is_nil_exempt', + print_hide=1) + taxable_value = dict(fieldname='taxable_value', label='Taxable Value', + fieldtype='Currency', insert_after='base_net_amount', hidden=1, options="Company:company:default_currency", + print_hide=1) + sales_invoice_gst_fields = [ + dict(fieldname='billing_address_gstin', label='Billing Address GSTIN', + fieldtype='Data', insert_after='customer_address', read_only=1, + fetch_from='customer_address.gstin', print_hide=1), + dict(fieldname='customer_gstin', label='Customer GSTIN', + fieldtype='Data', insert_after='shipping_address_name', + fetch_from='shipping_address_name.gstin', print_hide=1), + dict(fieldname='place_of_supply', label='Place of Supply', + fieldtype='Data', insert_after='customer_gstin', + print_hide=1, read_only=1), + dict(fieldname='company_gstin', label='Company GSTIN', + fieldtype='Data', insert_after='company_address', + fetch_from='company_address.gstin', print_hide=1, read_only=1), + ] + + custom_fields = { + 'POS Invoice': sales_invoice_gst_fields, + 'POS Invoice Item': [hsn_sac_field, nil_rated_exempt, is_non_gst, taxable_value], + } + + create_custom_fields(custom_fields, update=True) \ No newline at end of file diff --git a/erpnext/patches/v13_0/healthcare_deprecation_warning.py b/erpnext/patches/v13_0/healthcare_deprecation_warning.py new file mode 100644 index 00000000000..c6fba59371c --- /dev/null +++ b/erpnext/patches/v13_0/healthcare_deprecation_warning.py @@ -0,0 +1,10 @@ +import click + + +def execute(): + + click.secho( + "Healthcare Module is moved to a separate app and will be removed from ERPNext in version-14.\n" + "Please install the app to continue using the module: https://github.com/frappe/healthcare", + fg="yellow", + ) diff --git a/erpnext/patches/v13_0/healthcare_lab_module_rename_doctypes.py b/erpnext/patches/v13_0/healthcare_lab_module_rename_doctypes.py index f2976544a40..98ce12bc204 100644 --- a/erpnext/patches/v13_0/healthcare_lab_module_rename_doctypes.py +++ b/erpnext/patches/v13_0/healthcare_lab_module_rename_doctypes.py @@ -1,5 +1,3 @@ -from __future__ import unicode_literals - import frappe from frappe.model.utils.rename_field import rename_field diff --git a/erpnext/patches/v13_0/item_naming_series_not_mandatory.py b/erpnext/patches/v13_0/item_naming_series_not_mandatory.py new file mode 100644 index 00000000000..5fe85a48308 --- /dev/null +++ b/erpnext/patches/v13_0/item_naming_series_not_mandatory.py @@ -0,0 +1,11 @@ +import frappe + +from erpnext.setup.doctype.naming_series.naming_series import set_by_naming_series + + +def execute(): + + stock_settings = frappe.get_doc("Stock Settings") + + set_by_naming_series("Item", "item_code", + stock_settings.get("item_naming_by")=="Naming Series", hide_name_field=True, make_mandatory=0) diff --git a/erpnext/patches/v13_0/item_reposting_for_incorrect_sl_and_gl.py b/erpnext/patches/v13_0/item_reposting_for_incorrect_sl_and_gl.py index e4cb9ae7cdc..0f2ac4b4514 100644 --- a/erpnext/patches/v13_0/item_reposting_for_incorrect_sl_and_gl.py +++ b/erpnext/patches/v13_0/item_reposting_for_incorrect_sl_and_gl.py @@ -6,10 +6,19 @@ from erpnext.stock.stock_ledger import update_entries_after def execute(): - for doctype in ('repost_item_valuation', 'stock_entry_detail', 'purchase_receipt_item', - 'purchase_invoice_item', 'delivery_note_item', 'sales_invoice_item', 'packed_item'): - frappe.reload_doc('stock', 'doctype', doctype) - frappe.reload_doc('buying', 'doctype', 'purchase_receipt_item_supplied') + doctypes_to_reload = [ + ("stock", "repost_item_valuation"), + ("stock", "stock_entry_detail"), + ("stock", "purchase_receipt_item"), + ("stock", "delivery_note_item"), + ("stock", "packed_item"), + ("accounts", "sales_invoice_item"), + ("accounts", "purchase_invoice_item"), + ("buying", "purchase_receipt_item_supplied") + ] + + for module, doctype in doctypes_to_reload: + frappe.reload_doc(module, 'doctype', doctype) reposting_project_deployed_on = get_creation_time() posting_date = getdate(reposting_project_deployed_on) diff --git a/erpnext/patches/v13_0/loyalty_points_entry_for_pos_invoice.py b/erpnext/patches/v13_0/loyalty_points_entry_for_pos_invoice.py index 43c6c4941ea..68bcd8a8da5 100644 --- a/erpnext/patches/v13_0/loyalty_points_entry_for_pos_invoice.py +++ b/erpnext/patches/v13_0/loyalty_points_entry_for_pos_invoice.py @@ -1,7 +1,6 @@ # Copyright (c) 2019, Frappe and Contributors # License: GNU General Public License v3. See license.txt -from __future__ import unicode_literals import frappe diff --git a/erpnext/patches/v13_0/make_non_standard_user_type.py b/erpnext/patches/v13_0/make_non_standard_user_type.py index 746e4080b69..a7bdf93332a 100644 --- a/erpnext/patches/v13_0/make_non_standard_user_type.py +++ b/erpnext/patches/v13_0/make_non_standard_user_type.py @@ -1,10 +1,8 @@ # Copyright (c) 2019, Frappe and Contributors # License: GNU General Public License v3. See license.txt -from __future__ import unicode_literals import frappe -from six import iteritems from erpnext.setup.install import add_non_standard_user_types @@ -16,7 +14,7 @@ def execute(): 'hr': ['Employee', 'Expense Claim', 'Leave Application', 'Attendance Request', 'Compensatory Leave Request'] } - for module, doctypes in iteritems(doctype_dict): + for module, doctypes in doctype_dict.items(): for doctype in doctypes: frappe.reload_doc(module, 'doctype', doctype) diff --git a/erpnext/patches/v13_0/modify_invalid_gain_loss_gl_entries.py b/erpnext/patches/v13_0/modify_invalid_gain_loss_gl_entries.py new file mode 100644 index 00000000000..1c659980099 --- /dev/null +++ b/erpnext/patches/v13_0/modify_invalid_gain_loss_gl_entries.py @@ -0,0 +1,59 @@ +import json + +import frappe + + +def execute(): + frappe.reload_doc('accounts', 'doctype', 'purchase_invoice_advance') + frappe.reload_doc('accounts', 'doctype', 'sales_invoice_advance') + + purchase_invoices = frappe.db.sql(""" + select + parenttype as type, parent as name + from + `tabPurchase Invoice Advance` + where + ref_exchange_rate = 1 + and docstatus = 1 + and ifnull(exchange_gain_loss, 0) != 0 + group by + parent + """, as_dict=1) + + sales_invoices = frappe.db.sql(""" + select + parenttype as type, parent as name + from + `tabSales Invoice Advance` + where + ref_exchange_rate = 1 + and docstatus = 1 + and ifnull(exchange_gain_loss, 0) != 0 + group by + parent + """, as_dict=1) + + if purchase_invoices + sales_invoices: + frappe.log_error(json.dumps(purchase_invoices + sales_invoices, indent=2), title="Patch Log") + + acc_frozen_upto = frappe.db.get_value('Accounts Settings', None, 'acc_frozen_upto') + if acc_frozen_upto: + frappe.db.set_value('Accounts Settings', None, 'acc_frozen_upto', None) + + for invoice in purchase_invoices + sales_invoices: + try: + doc = frappe.get_doc(invoice.type, invoice.name) + doc.docstatus = 2 + doc.make_gl_entries() + for advance in doc.advances: + if advance.ref_exchange_rate == 1: + advance.db_set('exchange_gain_loss', 0, False) + doc.docstatus = 1 + doc.make_gl_entries() + frappe.db.commit() + except Exception: + frappe.db.rollback() + print(f'Failed to correct gl entries of {invoice.name}') + + if acc_frozen_upto: + frappe.db.set_value('Accounts Settings', None, 'acc_frozen_upto', acc_frozen_upto) \ No newline at end of file diff --git a/erpnext/patches/v13_0/move_branch_code_to_bank_account.py b/erpnext/patches/v13_0/move_branch_code_to_bank_account.py index 9116f5835a1..350744fd41f 100644 --- a/erpnext/patches/v13_0/move_branch_code_to_bank_account.py +++ b/erpnext/patches/v13_0/move_branch_code_to_bank_account.py @@ -1,7 +1,6 @@ # Copyright (c) 2019, Frappe and Contributors # License: GNU General Public License v3. See license.txt -from __future__ import unicode_literals import frappe diff --git a/erpnext/patches/v13_0/move_doctype_reports_and_notification_from_hr_to_payroll.py b/erpnext/patches/v13_0/move_doctype_reports_and_notification_from_hr_to_payroll.py index 064e8d71a04..c07caaef661 100644 --- a/erpnext/patches/v13_0/move_doctype_reports_and_notification_from_hr_to_payroll.py +++ b/erpnext/patches/v13_0/move_doctype_reports_and_notification_from_hr_to_payroll.py @@ -1,7 +1,6 @@ # Copyright (c) 2019, Frappe and Contributors # License: GNU General Public License v3. See license.txt -from __future__ import unicode_literals import frappe diff --git a/erpnext/patches/v13_0/move_payroll_setting_separately_from_hr_settings.py b/erpnext/patches/v13_0/move_payroll_setting_separately_from_hr_settings.py index 85d5109248d..fca7c09c91a 100644 --- a/erpnext/patches/v13_0/move_payroll_setting_separately_from_hr_settings.py +++ b/erpnext/patches/v13_0/move_payroll_setting_separately_from_hr_settings.py @@ -1,7 +1,6 @@ # Copyright (c) 2019, Frappe and Contributors # License: GNU General Public License v3. See license.txt -from __future__ import unicode_literals import frappe diff --git a/erpnext/patches/v13_0/move_tax_slabs_from_payroll_period_to_income_tax_slab.py b/erpnext/patches/v13_0/move_tax_slabs_from_payroll_period_to_income_tax_slab.py index e73fa7b9ecd..d1ea22f7f26 100644 --- a/erpnext/patches/v13_0/move_tax_slabs_from_payroll_period_to_income_tax_slab.py +++ b/erpnext/patches/v13_0/move_tax_slabs_from_payroll_period_to_income_tax_slab.py @@ -1,7 +1,6 @@ # Copyright (c) 2019, Frappe and Contributors # License: GNU General Public License v3. See license.txt -from __future__ import unicode_literals import frappe diff --git a/erpnext/patches/v13_0/patch_to_fix_reverse_linking_in_additional_salary_encashment_and_incentive.py b/erpnext/patches/v13_0/patch_to_fix_reverse_linking_in_additional_salary_encashment_and_incentive.py index bb539a7962c..7c10a313a56 100644 --- a/erpnext/patches/v13_0/patch_to_fix_reverse_linking_in_additional_salary_encashment_and_incentive.py +++ b/erpnext/patches/v13_0/patch_to_fix_reverse_linking_in_additional_salary_encashment_and_incentive.py @@ -1,5 +1,3 @@ -from __future__ import unicode_literals - import frappe diff --git a/erpnext/patches/v13_0/print_uom_after_quantity_patch.py b/erpnext/patches/v13_0/print_uom_after_quantity_patch.py index f2022b28b8b..3da6f749aff 100644 --- a/erpnext/patches/v13_0/print_uom_after_quantity_patch.py +++ b/erpnext/patches/v13_0/print_uom_after_quantity_patch.py @@ -1,7 +1,6 @@ # Copyright (c) 2019, Frappe and Contributors # License: GNU General Public License v3. See license.txt -from __future__ import unicode_literals from erpnext.setup.install import create_print_uom_after_qty_custom_field diff --git a/erpnext/patches/v13_0/rename_discharge_date_in_ip_record.py b/erpnext/patches/v13_0/rename_discharge_date_in_ip_record.py index 2a04211a407..3bd717d77b8 100644 --- a/erpnext/patches/v13_0/rename_discharge_date_in_ip_record.py +++ b/erpnext/patches/v13_0/rename_discharge_date_in_ip_record.py @@ -1,5 +1,3 @@ -from __future__ import unicode_literals - import frappe from frappe.model.utils.rename_field import rename_field diff --git a/erpnext/patches/v13_0/rename_issue_doctype_fields.py b/erpnext/patches/v13_0/rename_issue_doctype_fields.py index 4aeafeabe74..bf5438c4d2e 100644 --- a/erpnext/patches/v13_0/rename_issue_doctype_fields.py +++ b/erpnext/patches/v13_0/rename_issue_doctype_fields.py @@ -1,7 +1,6 @@ # Copyright (c) 2020, Frappe and Contributors # License: GNU General Public License v3. See license.txt -from __future__ import unicode_literals import frappe from frappe.model.utils.rename_field import rename_field diff --git a/erpnext/patches/v13_0/rename_issue_status_hold_to_on_hold.py b/erpnext/patches/v13_0/rename_issue_status_hold_to_on_hold.py index 1d245db4d59..b129cbe80bc 100644 --- a/erpnext/patches/v13_0/rename_issue_status_hold_to_on_hold.py +++ b/erpnext/patches/v13_0/rename_issue_status_hold_to_on_hold.py @@ -1,7 +1,6 @@ # Copyright (c) 2020, Frappe and Contributors # License: GNU General Public License v3. See license.txt -from __future__ import unicode_literals import frappe diff --git a/erpnext/patches/v13_0/rename_membership_settings_to_non_profit_settings.py b/erpnext/patches/v13_0/rename_membership_settings_to_non_profit_settings.py index 23a782a1e82..265e2a9b0cf 100644 --- a/erpnext/patches/v13_0/rename_membership_settings_to_non_profit_settings.py +++ b/erpnext/patches/v13_0/rename_membership_settings_to_non_profit_settings.py @@ -1,5 +1,3 @@ -from __future__ import unicode_literals - import frappe from frappe.model.utils.rename_field import rename_field diff --git a/erpnext/patches/v13_0/replace_pos_page_with_point_of_sale_page.py b/erpnext/patches/v13_0/replace_pos_page_with_point_of_sale_page.py index 989f1a0a281..7d757b7a0fb 100644 --- a/erpnext/patches/v13_0/replace_pos_page_with_point_of_sale_page.py +++ b/erpnext/patches/v13_0/replace_pos_page_with_point_of_sale_page.py @@ -1,5 +1,3 @@ -from __future__ import unicode_literals - import frappe diff --git a/erpnext/patches/v13_0/replace_pos_payment_mode_table.py b/erpnext/patches/v13_0/replace_pos_payment_mode_table.py index 103c79177f1..a2c960c8f37 100644 --- a/erpnext/patches/v13_0/replace_pos_payment_mode_table.py +++ b/erpnext/patches/v13_0/replace_pos_payment_mode_table.py @@ -1,7 +1,6 @@ # Copyright (c) 2019, Frappe and Contributors # License: GNU General Public License v3. See license.txt -from __future__ import unicode_literals import frappe diff --git a/erpnext/patches/v13_0/replace_supplier_item_group_with_party_specific_item.py b/erpnext/patches/v13_0/replace_supplier_item_group_with_party_specific_item.py new file mode 100644 index 00000000000..ba96fdd2266 --- /dev/null +++ b/erpnext/patches/v13_0/replace_supplier_item_group_with_party_specific_item.py @@ -0,0 +1,17 @@ +# Copyright (c) 2019, Frappe and Contributors +# License: GNU General Public License v3. See license.txt + +import frappe + + +def execute(): + if frappe.db.table_exists('Supplier Item Group'): + frappe.reload_doc("selling", "doctype", "party_specific_item") + sig = frappe.db.get_all("Supplier Item Group", fields=["name", "supplier", "item_group"]) + for item in sig: + psi = frappe.new_doc("Party Specific Item") + psi.party_type = "Supplier" + psi.party = item.supplier + psi.restrict_based_on = "Item Group" + psi.based_on_value = item.item_group + psi.insert() diff --git a/erpnext/patches/v13_0/requeue_failed_reposts.py b/erpnext/patches/v13_0/requeue_failed_reposts.py new file mode 100644 index 00000000000..213cb9e26e4 --- /dev/null +++ b/erpnext/patches/v13_0/requeue_failed_reposts.py @@ -0,0 +1,13 @@ +import frappe +from frappe.utils import cstr + + +def execute(): + + reposts = frappe.get_all("Repost Item Valuation", + {"status": "Failed", "modified": [">", "2021-10-05"] }, + ["name", "modified", "error_log"]) + + for repost in reposts: + if "check_freezing_date" in cstr(repost.error_log): + frappe.db.set_value("Repost Item Valuation", repost.name, "status", "Queued") diff --git a/erpnext/patches/v13_0/reset_clearance_date_for_intracompany_payment_entries.py b/erpnext/patches/v13_0/reset_clearance_date_for_intracompany_payment_entries.py index 29343b71bf7..69fc6a2dbcf 100644 --- a/erpnext/patches/v13_0/reset_clearance_date_for_intracompany_payment_entries.py +++ b/erpnext/patches/v13_0/reset_clearance_date_for_intracompany_payment_entries.py @@ -1,7 +1,6 @@ # Copyright (c) 2019, Frappe and Contributors # License: GNU General Public License v3. See license.txt -from __future__ import unicode_literals import frappe diff --git a/erpnext/patches/v13_0/set_company_field_in_healthcare_doctypes.py b/erpnext/patches/v13_0/set_company_field_in_healthcare_doctypes.py index e9396c2df29..f82a0d56e0c 100644 --- a/erpnext/patches/v13_0/set_company_field_in_healthcare_doctypes.py +++ b/erpnext/patches/v13_0/set_company_field_in_healthcare_doctypes.py @@ -1,5 +1,3 @@ -from __future__ import unicode_literals - import frappe diff --git a/erpnext/patches/v13_0/set_payment_channel_in_payment_gateway_account.py b/erpnext/patches/v13_0/set_payment_channel_in_payment_gateway_account.py index da889e61bab..87b3389448a 100644 --- a/erpnext/patches/v13_0/set_payment_channel_in_payment_gateway_account.py +++ b/erpnext/patches/v13_0/set_payment_channel_in_payment_gateway_account.py @@ -1,5 +1,3 @@ -from __future__ import unicode_literals - import frappe diff --git a/erpnext/patches/v13_0/set_pos_closing_as_failed.py b/erpnext/patches/v13_0/set_pos_closing_as_failed.py index 8c7f5088b74..6a3785d8377 100644 --- a/erpnext/patches/v13_0/set_pos_closing_as_failed.py +++ b/erpnext/patches/v13_0/set_pos_closing_as_failed.py @@ -1,5 +1,3 @@ -from __future__ import unicode_literals - import frappe diff --git a/erpnext/patches/v13_0/set_status_in_maintenance_schedule_table.py b/erpnext/patches/v13_0/set_status_in_maintenance_schedule_table.py new file mode 100644 index 00000000000..9887ad9df0c --- /dev/null +++ b/erpnext/patches/v13_0/set_status_in_maintenance_schedule_table.py @@ -0,0 +1,10 @@ +import frappe + + +def execute(): + frappe.reload_doc("maintenance", "doctype", "Maintenance Schedule Detail") + frappe.db.sql(""" + UPDATE `tabMaintenance Schedule Detail` + SET completion_status = 'Pending' + WHERE docstatus < 2 + """) diff --git a/erpnext/patches/v13_0/set_training_event_attendance.py b/erpnext/patches/v13_0/set_training_event_attendance.py index 4e3d8f5e6a5..e44f32157dc 100644 --- a/erpnext/patches/v13_0/set_training_event_attendance.py +++ b/erpnext/patches/v13_0/set_training_event_attendance.py @@ -1,5 +1,3 @@ -from __future__ import unicode_literals - import frappe diff --git a/erpnext/patches/v13_0/set_youtube_video_id.py b/erpnext/patches/v13_0/set_youtube_video_id.py index 1594e52e4e5..e1eb1b9bc2f 100644 --- a/erpnext/patches/v13_0/set_youtube_video_id.py +++ b/erpnext/patches/v13_0/set_youtube_video_id.py @@ -1,5 +1,3 @@ -from __future__ import unicode_literals - import frappe from erpnext.utilities.doctype.video.video import get_id_from_url diff --git a/erpnext/patches/v13_0/setting_custom_roles_for_some_regional_reports.py b/erpnext/patches/v13_0/setting_custom_roles_for_some_regional_reports.py index a6a3ff3be4b..dc3f8aadc16 100644 --- a/erpnext/patches/v13_0/setting_custom_roles_for_some_regional_reports.py +++ b/erpnext/patches/v13_0/setting_custom_roles_for_some_regional_reports.py @@ -1,5 +1,3 @@ -from __future__ import unicode_literals - import frappe from erpnext.regional.india.setup import add_custom_roles_for_reports diff --git a/erpnext/patches/v13_0/setup_gratuity_rule_for_india_and_uae.py b/erpnext/patches/v13_0/setup_gratuity_rule_for_india_and_uae.py index 01e75a6009b..82cc1ff771c 100644 --- a/erpnext/patches/v13_0/setup_gratuity_rule_for_india_and_uae.py +++ b/erpnext/patches/v13_0/setup_gratuity_rule_for_india_and_uae.py @@ -1,7 +1,6 @@ # Copyright (c) 2019, Frappe and Contributors # License: GNU General Public License v3. See license.txt -from __future__ import unicode_literals import frappe diff --git a/erpnext/patches/v13_0/setup_patient_history_settings_for_standard_doctypes.py b/erpnext/patches/v13_0/setup_patient_history_settings_for_standard_doctypes.py deleted file mode 100644 index 80622d46096..00000000000 --- a/erpnext/patches/v13_0/setup_patient_history_settings_for_standard_doctypes.py +++ /dev/null @@ -1,19 +0,0 @@ -from __future__ import unicode_literals - -import frappe - -from erpnext.healthcare.setup import setup_patient_history_settings - - -def execute(): - if "Healthcare" not in frappe.get_active_domains(): - return - - frappe.reload_doc("healthcare", "doctype", "Inpatient Medication Order") - frappe.reload_doc("healthcare", "doctype", "Therapy Session") - frappe.reload_doc("healthcare", "doctype", "Clinical Procedure") - frappe.reload_doc("healthcare", "doctype", "Patient History Settings") - frappe.reload_doc("healthcare", "doctype", "Patient History Standard Document Type") - frappe.reload_doc("healthcare", "doctype", "Patient History Custom Document Type") - - setup_patient_history_settings() diff --git a/erpnext/patches/v13_0/stock_entry_enhancements.py b/erpnext/patches/v13_0/stock_entry_enhancements.py index 5fcd6a3a625..968a83a4212 100644 --- a/erpnext/patches/v13_0/stock_entry_enhancements.py +++ b/erpnext/patches/v13_0/stock_entry_enhancements.py @@ -1,7 +1,6 @@ # Copyright(c) 2020, Frappe Technologies Pvt.Ltd.and Contributors # License: GNU General Public License v3.See license.txt -from __future__ import unicode_literals import frappe diff --git a/erpnext/patches/v13_0/trim_sales_invoice_custom_field_length.py b/erpnext/patches/v13_0/trim_sales_invoice_custom_field_length.py new file mode 100644 index 00000000000..fd48c0d902d --- /dev/null +++ b/erpnext/patches/v13_0/trim_sales_invoice_custom_field_length.py @@ -0,0 +1,18 @@ +# Copyright (c) 2020, Frappe and Contributors +# License: GNU General Public License v3. See license.txt + +import frappe + +from erpnext.regional.india.setup import create_custom_fields, get_custom_fields + + +def execute(): + company = frappe.get_all('Company', filters = {'country': 'India'}) + if not company: + return + + custom_fields = { + 'Sales Invoice': get_custom_fields().get('Sales Invoice') + } + + create_custom_fields(custom_fields, update=True) diff --git a/erpnext/patches/v13_0/update_actual_start_and_end_date_in_wo.py b/erpnext/patches/v13_0/update_actual_start_and_end_date_in_wo.py index dd87a5302d2..55fd465b204 100644 --- a/erpnext/patches/v13_0/update_actual_start_and_end_date_in_wo.py +++ b/erpnext/patches/v13_0/update_actual_start_and_end_date_in_wo.py @@ -1,8 +1,6 @@ - # Copyright (c) 2019, Frappe and Contributors # License: GNU General Public License v3. See license.txt -from __future__ import unicode_literals import frappe from frappe.utils import add_to_date diff --git a/erpnext/patches/v13_0/update_category_in_ltds_certificate.py b/erpnext/patches/v13_0/update_category_in_ltds_certificate.py new file mode 100644 index 00000000000..a5f5a23449a --- /dev/null +++ b/erpnext/patches/v13_0/update_category_in_ltds_certificate.py @@ -0,0 +1,20 @@ +import frappe + + +def execute(): + company = frappe.get_all('Company', filters = {'country': 'India'}) + if not company: + return + + frappe.reload_doc('regional', 'doctype', 'lower_deduction_certificate') + + ldc = frappe.qb.DocType("Lower Deduction Certificate").as_("ldc") + supplier = frappe.qb.DocType("Supplier") + + frappe.qb.update(ldc).inner_join(supplier).on( + ldc.supplier == supplier.name + ).set( + ldc.tax_withholding_category, supplier.tax_withholding_category + ).where( + ldc.tax_withholding_category.isnull() + ).run() \ No newline at end of file diff --git a/erpnext/patches/v13_0/update_dates_in_tax_withholding_category.py b/erpnext/patches/v13_0/update_dates_in_tax_withholding_category.py new file mode 100644 index 00000000000..90fb50fb42c --- /dev/null +++ b/erpnext/patches/v13_0/update_dates_in_tax_withholding_category.py @@ -0,0 +1,26 @@ +# Copyright (c) 2021, Frappe and Contributors +# License: GNU General Public License v3. See license.txt + +import frappe + + +def execute(): + frappe.reload_doc('accounts', 'doctype', 'Tax Withholding Rate') + + if frappe.db.has_column('Tax Withholding Rate', 'fiscal_year'): + tds_category_rates = frappe.get_all('Tax Withholding Rate', fields=['name', 'fiscal_year']) + + fiscal_year_map = {} + fiscal_year_details = frappe.get_all('Fiscal Year', fields=['name', 'year_start_date', 'year_end_date']) + + for d in fiscal_year_details: + fiscal_year_map.setdefault(d.name, d) + + for rate in tds_category_rates: + from_date = fiscal_year_map.get(rate.fiscal_year).get('year_start_date') + to_date = fiscal_year_map.get(rate.fiscal_year).get('year_end_date') + + frappe.db.set_value('Tax Withholding Rate', rate.name, { + 'from_date': from_date, + 'to_date': to_date + }) \ No newline at end of file diff --git a/erpnext/patches/v13_0/update_deferred_settings.py b/erpnext/patches/v13_0/update_deferred_settings.py index 54059318c75..1b63635b678 100644 --- a/erpnext/patches/v13_0/update_deferred_settings.py +++ b/erpnext/patches/v13_0/update_deferred_settings.py @@ -1,6 +1,5 @@ # Copyright (c) 2019, Frappe and Contributors # License: GNU General Public License v3. See license.txt -from __future__ import unicode_literals import frappe diff --git a/erpnext/patches/v13_0/update_job_card_details.py b/erpnext/patches/v13_0/update_job_card_details.py index a0405e50396..12f9006b76e 100644 --- a/erpnext/patches/v13_0/update_job_card_details.py +++ b/erpnext/patches/v13_0/update_job_card_details.py @@ -1,7 +1,6 @@ # Copyright (c) 2019, Frappe and Contributors # License: GNU General Public License v3. See license.txt -from __future__ import unicode_literals import frappe diff --git a/erpnext/patches/v13_0/update_job_card_status.py b/erpnext/patches/v13_0/update_job_card_status.py new file mode 100644 index 00000000000..797a3e2ae35 --- /dev/null +++ b/erpnext/patches/v13_0/update_job_card_status.py @@ -0,0 +1,18 @@ +# Copyright (c) 2021, Frappe and Contributors +# License: GNU General Public License v3. See license.txt + +import frappe + + +def execute(): + + job_card = frappe.qb.DocType("Job Card") + (frappe.qb + .update(job_card) + .set(job_card.status, "Completed") + .where( + (job_card.docstatus == 1) + & (job_card.for_quantity <= job_card.total_completed_qty) + & (job_card.status.isin(["Work In Progress", "Material Transferred"])) + ) + ).run() diff --git a/erpnext/patches/v13_0/update_level_in_bom.py b/erpnext/patches/v13_0/update_level_in_bom.py index 6223500e6b6..499412ee270 100644 --- a/erpnext/patches/v13_0/update_level_in_bom.py +++ b/erpnext/patches/v13_0/update_level_in_bom.py @@ -1,7 +1,6 @@ # Copyright (c) 2020, Frappe and Contributors # License: GNU General Public License v3. See license.txt -from __future__ import unicode_literals import frappe diff --git a/erpnext/patches/v13_0/update_member_email_address.py b/erpnext/patches/v13_0/update_member_email_address.py index 769658e2b8a..e4bc1b3e5c7 100644 --- a/erpnext/patches/v13_0/update_member_email_address.py +++ b/erpnext/patches/v13_0/update_member_email_address.py @@ -1,7 +1,6 @@ # Copyright (c) 2020, Frappe Technologies Pvt. Ltd. and Contributors # MIT License. See license.txt -from __future__ import unicode_literals import frappe from frappe.model.utils.rename_field import rename_field diff --git a/erpnext/patches/v13_0/update_old_loans.py b/erpnext/patches/v13_0/update_old_loans.py index b01a87722ef..e226f1dd567 100644 --- a/erpnext/patches/v13_0/update_old_loans.py +++ b/erpnext/patches/v13_0/update_old_loans.py @@ -1,5 +1,3 @@ -from __future__ import unicode_literals - import frappe from frappe import _ from frappe.model.naming import make_autoname diff --git a/erpnext/patches/v13_0/update_payment_terms_outstanding.py b/erpnext/patches/v13_0/update_payment_terms_outstanding.py index c9e920b7cb5..aea09ad7a37 100644 --- a/erpnext/patches/v13_0/update_payment_terms_outstanding.py +++ b/erpnext/patches/v13_0/update_payment_terms_outstanding.py @@ -1,7 +1,6 @@ # Copyright (c) 2020, Frappe Technologies Pvt. Ltd. and Contributors # MIT License. See license.txt -from __future__ import unicode_literals import frappe diff --git a/erpnext/patches/v13_0/update_pos_closing_entry_in_merge_log.py b/erpnext/patches/v13_0/update_pos_closing_entry_in_merge_log.py index 71fe9ed6805..b2e35591970 100644 --- a/erpnext/patches/v13_0/update_pos_closing_entry_in_merge_log.py +++ b/erpnext/patches/v13_0/update_pos_closing_entry_in_merge_log.py @@ -1,7 +1,6 @@ # Copyright (c) 2020, Frappe Technologies Pvt. Ltd. and Contributors # MIT License. See license.txt -from __future__ import unicode_literals import frappe diff --git a/erpnext/patches/v13_0/update_project_template_tasks.py b/erpnext/patches/v13_0/update_project_template_tasks.py index f0d0a5a7ef5..29debc6ad14 100644 --- a/erpnext/patches/v13_0/update_project_template_tasks.py +++ b/erpnext/patches/v13_0/update_project_template_tasks.py @@ -1,7 +1,6 @@ # Copyright (c) 2019, Frappe and Contributors # License: GNU General Public License v3. See license.txt -from __future__ import unicode_literals import frappe diff --git a/erpnext/patches/v13_0/update_reason_for_resignation_in_employee.py b/erpnext/patches/v13_0/update_reason_for_resignation_in_employee.py index 84075024a47..f9bfc54502f 100644 --- a/erpnext/patches/v13_0/update_reason_for_resignation_in_employee.py +++ b/erpnext/patches/v13_0/update_reason_for_resignation_in_employee.py @@ -1,7 +1,6 @@ # Copyright (c) 2020, Frappe Technologies Pvt. Ltd. and Contributors # MIT License. See license.txt -from __future__ import unicode_literals import frappe diff --git a/erpnext/patches/v13_0/update_recipient_email_digest.py b/erpnext/patches/v13_0/update_recipient_email_digest.py index f4a48107c45..d4d45afabaf 100644 --- a/erpnext/patches/v13_0/update_recipient_email_digest.py +++ b/erpnext/patches/v13_0/update_recipient_email_digest.py @@ -1,7 +1,6 @@ # Copyright (c) 2020, Frappe and Contributors # License: GNU General Public License v3. See license.txt -from __future__ import unicode_literals import frappe diff --git a/erpnext/patches/v13_0/update_response_by_variance.py b/erpnext/patches/v13_0/update_response_by_variance.py index 444ec9ecb98..d65e9035c0e 100644 --- a/erpnext/patches/v13_0/update_response_by_variance.py +++ b/erpnext/patches/v13_0/update_response_by_variance.py @@ -1,7 +1,6 @@ # Copyright (c) 2020, Frappe and Contributors # License: GNU General Public License v3. See license.txt -from __future__ import unicode_literals import frappe diff --git a/erpnext/patches/v13_0/update_returned_qty_in_pr_dn.py b/erpnext/patches/v13_0/update_returned_qty_in_pr_dn.py index efb3a5961f9..dd64e05ec16 100644 --- a/erpnext/patches/v13_0/update_returned_qty_in_pr_dn.py +++ b/erpnext/patches/v13_0/update_returned_qty_in_pr_dn.py @@ -13,7 +13,7 @@ def execute(): frappe.reload_doc('stock', 'doctype', 'stock_settings') def update_from_return_docs(doctype): - for return_doc in frappe.get_all(doctype, filters={'is_return' : 1, 'docstatus' : 1}): + for return_doc in frappe.get_all(doctype, filters={'is_return' : 1, 'docstatus' : 1, 'return_against': ('!=', '')}): # Update original receipt/delivery document from return return_doc = frappe.get_cached_doc(doctype, return_doc.name) try: diff --git a/erpnext/patches/v13_0/update_sla_enhancements.py b/erpnext/patches/v13_0/update_sla_enhancements.py index bcfbf8b24cb..7f61020309d 100644 --- a/erpnext/patches/v13_0/update_sla_enhancements.py +++ b/erpnext/patches/v13_0/update_sla_enhancements.py @@ -1,7 +1,6 @@ # Copyright (c) 2018, Frappe and Contributors # License: GNU General Public License v3. See license.txt -from __future__ import unicode_literals import frappe diff --git a/erpnext/patches/v13_0/update_start_end_date_for_old_shift_assignment.py b/erpnext/patches/v13_0/update_start_end_date_for_old_shift_assignment.py index bcdf72ec69c..665cc39923a 100644 --- a/erpnext/patches/v13_0/update_start_end_date_for_old_shift_assignment.py +++ b/erpnext/patches/v13_0/update_start_end_date_for_old_shift_assignment.py @@ -1,7 +1,6 @@ # Copyright (c) 2019, Frappe and Contributors # License: GNU General Public License v3. See license.txt -from __future__ import unicode_literals import frappe diff --git a/erpnext/patches/v13_0/update_subscription.py b/erpnext/patches/v13_0/update_subscription.py index e0ea78fa4d9..b67c74de1d2 100644 --- a/erpnext/patches/v13_0/update_subscription.py +++ b/erpnext/patches/v13_0/update_subscription.py @@ -1,10 +1,8 @@ # Copyright (c) 2019, Frappe and Contributors # License: GNU General Public License v3. See license.txt -from __future__ import unicode_literals import frappe -from six import iteritems def execute(): @@ -35,7 +33,7 @@ def execute(): 'Based on price list': 'Based On Price List' } - for key, value in iteritems(price_determination_map): + for key, value in price_determination_map.items(): frappe.db.sql(""" UPDATE `tabSubscription Plan` SET price_determination = %s diff --git a/erpnext/patches/v13_0/update_timesheet_changes.py b/erpnext/patches/v13_0/update_timesheet_changes.py index d993d54191f..a5e3391d531 100644 --- a/erpnext/patches/v13_0/update_timesheet_changes.py +++ b/erpnext/patches/v13_0/update_timesheet_changes.py @@ -1,5 +1,3 @@ -from __future__ import unicode_literals - import frappe from frappe.model.utils.rename_field import rename_field diff --git a/erpnext/patches/v12_0/update_vehicle_no_reqd_condition.py b/erpnext/patches/v13_0/update_vehicle_no_reqd_condition.py similarity index 81% rename from erpnext/patches/v12_0/update_vehicle_no_reqd_condition.py rename to erpnext/patches/v13_0/update_vehicle_no_reqd_condition.py index 69bfaaa2cb1..902707b4b66 100644 --- a/erpnext/patches/v12_0/update_vehicle_no_reqd_condition.py +++ b/erpnext/patches/v13_0/update_vehicle_no_reqd_condition.py @@ -2,7 +2,7 @@ import frappe def execute(): - frappe.reload_doc('custom', 'doctype', 'custom_field') + frappe.reload_doc('custom', 'doctype', 'custom_field', force=True) company = frappe.get_all('Company', filters = {'country': 'India'}) if not company: return diff --git a/erpnext/patches/v13_0/validate_options_for_data_field.py b/erpnext/patches/v13_0/validate_options_for_data_field.py index 41a38fe29c1..ad777b8586d 100644 --- a/erpnext/patches/v13_0/validate_options_for_data_field.py +++ b/erpnext/patches/v13_0/validate_options_for_data_field.py @@ -1,7 +1,6 @@ # Copyright (c) 2021, Frappe and Contributors # License: GNU General Public License v3. See license.txt -from __future__ import unicode_literals import frappe from frappe.model import data_field_options diff --git a/erpnext/patches/v14_0/delete_healthcare_doctypes.py b/erpnext/patches/v14_0/delete_healthcare_doctypes.py new file mode 100644 index 00000000000..28fc01beab5 --- /dev/null +++ b/erpnext/patches/v14_0/delete_healthcare_doctypes.py @@ -0,0 +1,49 @@ +import frappe + + +def execute(): + if "healthcare" in frappe.get_installed_apps(): + return + + frappe.delete_doc("Workspace", "Healthcare", ignore_missing=True, force=True) + + pages = frappe.get_all("Page", {"module": "healthcare"}, pluck='name') + for page in pages: + frappe.delete_doc("Page", page, ignore_missing=True, force=True) + + reports = frappe.get_all("Report", {"module": "healthcare", "is_standard": "Yes"}, pluck='name') + for report in reports: + frappe.delete_doc("Report", report, ignore_missing=True, force=True) + + print_formats = frappe.get_all("Print Format", {"module": "healthcare", "standard": "Yes"}, pluck='name') + for print_format in print_formats: + frappe.delete_doc("Print Format", print_format, ignore_missing=True, force=True) + + frappe.reload_doc("website", "doctype", "website_settings") + forms = frappe.get_all("Web Form", {"module": "healthcare", "is_standard": 1}, pluck='name') + for form in forms: + frappe.delete_doc("Web Form", form, ignore_missing=True, force=True) + + dashboards = frappe.get_all("Dashboard", {"module": "healthcare", "is_standard": 1}, pluck='name') + for dashboard in dashboards: + frappe.delete_doc("Dashboard", dashboard, ignore_missing=True, force=True) + + dashboards = frappe.get_all("Dashboard Chart", {"module": "healthcare", "is_standard": 1}, pluck='name') + for dashboard in dashboards: + frappe.delete_doc("Dashboard Chart", dashboard, ignore_missing=True, force=True) + + frappe.reload_doc("desk", "doctype", "number_card") + cards = frappe.get_all("Number Card", {"module": "healthcare", "is_standard": 1}, pluck='name') + for card in cards: + frappe.delete_doc("Number Card", card, ignore_missing=True, force=True) + + titles = ['Lab Test', 'Prescription', 'Patient Appointment'] + items = frappe.get_all('Portal Menu Item', filters=[['title', 'in', titles]], pluck='name') + for item in items: + frappe.delete_doc("Portal Menu Item", item, ignore_missing=True, force=True) + + doctypes = frappe.get_all("DocType", {"module": "healthcare", "custom": 0}, pluck='name') + for doctype in doctypes: + frappe.delete_doc("DocType", doctype, ignore_missing=True) + + frappe.delete_doc("Module Def", "Healthcare", ignore_missing=True, force=True) diff --git a/erpnext/patches/v14_0/delete_hub_doctypes.py b/erpnext/patches/v14_0/delete_hub_doctypes.py new file mode 100644 index 00000000000..d1e9e31f0c2 --- /dev/null +++ b/erpnext/patches/v14_0/delete_hub_doctypes.py @@ -0,0 +1,10 @@ +import frappe + + +def execute(): + + doctypes = frappe.get_all("DocType", {"module": "Hub Node", "custom": 0}, pluck='name') + for doctype in doctypes: + frappe.delete_doc("DocType", doctype, ignore_missing=True) + + frappe.delete_doc("Module Def", "Hub Node", ignore_missing=True, force=True) diff --git a/erpnext/patches/v14_0/update_opportunity_currency_fields.py b/erpnext/patches/v14_0/update_opportunity_currency_fields.py new file mode 100644 index 00000000000..13071478c86 --- /dev/null +++ b/erpnext/patches/v14_0/update_opportunity_currency_fields.py @@ -0,0 +1,34 @@ +import frappe +from frappe.utils import flt + +import erpnext +from erpnext.setup.utils import get_exchange_rate + + +def execute(): + frappe.reload_doc('crm', 'doctype', 'opportunity') + frappe.reload_doc('crm', 'doctype', 'opportunity_item') + + opportunities = frappe.db.get_list('Opportunity', filters={ + 'opportunity_amount': ['>', 0] + }, fields=['name', 'company', 'currency', 'opportunity_amount']) + + for opportunity in opportunities: + company_currency = erpnext.get_company_currency(opportunity.company) + + # base total and total will be 0 only since item table did not have amount field earlier + if opportunity.currency != company_currency: + conversion_rate = get_exchange_rate(opportunity.currency, company_currency) + base_opportunity_amount = flt(conversion_rate) * flt(opportunity.opportunity_amount) + grand_total = flt(opportunity.opportunity_amount) + base_grand_total = flt(conversion_rate) * flt(opportunity.opportunity_amount) + else: + conversion_rate = 1 + base_opportunity_amount = grand_total = base_grand_total = flt(opportunity.opportunity_amount) + + frappe.db.set_value('Opportunity', opportunity.name, { + 'conversion_rate': conversion_rate, + 'base_opportunity_amount': base_opportunity_amount, + 'grand_total': grand_total, + 'base_grand_total': base_grand_total + }, update_modified=False) diff --git a/erpnext/patches/v4_2/repost_reserved_qty.py b/erpnext/patches/v4_2/repost_reserved_qty.py index 4fa3b468719..c2ca9be64aa 100644 --- a/erpnext/patches/v4_2/repost_reserved_qty.py +++ b/erpnext/patches/v4_2/repost_reserved_qty.py @@ -1,7 +1,6 @@ # Copyright (c) 2013, Web Notes Technologies Pvt. Ltd. and Contributors # License: GNU General Public License v3. See license.txt -from __future__ import unicode_literals import frappe diff --git a/erpnext/patches/v4_2/update_requested_and_ordered_qty.py b/erpnext/patches/v4_2/update_requested_and_ordered_qty.py index 9330a443bf3..42b0b04076f 100644 --- a/erpnext/patches/v4_2/update_requested_and_ordered_qty.py +++ b/erpnext/patches/v4_2/update_requested_and_ordered_qty.py @@ -1,7 +1,6 @@ # Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors # License: GNU General Public License v3. See license.txt -from __future__ import unicode_literals import frappe diff --git a/erpnext/patches/v5_7/update_item_description_based_on_item_master.py b/erpnext/patches/v5_7/update_item_description_based_on_item_master.py index 82b5b1cc2d2..c46187ca114 100644 --- a/erpnext/patches/v5_7/update_item_description_based_on_item_master.py +++ b/erpnext/patches/v5_7/update_item_description_based_on_item_master.py @@ -1,5 +1,3 @@ -from __future__ import unicode_literals - import frappe diff --git a/erpnext/patches/v8_1/removed_roles_from_gst_report_non_indian_account.py b/erpnext/patches/v8_1/removed_roles_from_gst_report_non_indian_account.py index ecfdc41f9b8..ed1dffe75c8 100644 --- a/erpnext/patches/v8_1/removed_roles_from_gst_report_non_indian_account.py +++ b/erpnext/patches/v8_1/removed_roles_from_gst_report_non_indian_account.py @@ -1,7 +1,6 @@ # Copyright (c) 2017, Frappe and Contributors # License: GNU General Public License v3. See license.txt -from __future__ import unicode_literals import frappe diff --git a/erpnext/patches/v8_1/setup_gst_india.py b/erpnext/patches/v8_1/setup_gst_india.py index 140b22656b1..ff9e6a48e83 100644 --- a/erpnext/patches/v8_1/setup_gst_india.py +++ b/erpnext/patches/v8_1/setup_gst_india.py @@ -1,5 +1,3 @@ -from __future__ import unicode_literals - import frappe from frappe.email import sendmail_to_system_managers diff --git a/erpnext/patches/v8_7/sync_india_custom_fields.py b/erpnext/patches/v8_7/sync_india_custom_fields.py index 65ec14e8826..808c833f6fc 100644 --- a/erpnext/patches/v8_7/sync_india_custom_fields.py +++ b/erpnext/patches/v8_7/sync_india_custom_fields.py @@ -1,5 +1,3 @@ -from __future__ import unicode_literals - import frappe from erpnext.regional.india.setup import make_custom_fields diff --git a/erpnext/payroll/doctype/additional_salary/additional_salary.py b/erpnext/payroll/doctype/additional_salary/additional_salary.py index ed10f2bc67a..bf8bd05fcc0 100644 --- a/erpnext/payroll/doctype/additional_salary/additional_salary.py +++ b/erpnext/payroll/doctype/additional_salary/additional_salary.py @@ -1,8 +1,6 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2018, Frappe Technologies Pvt. Ltd. and contributors # For license information, please see license.txt -from __future__ import unicode_literals import frappe from frappe import _, bold @@ -14,12 +12,11 @@ from erpnext.hr.utils import validate_active_employee class AdditionalSalary(Document): def on_submit(self): - if self.ref_doctype == "Employee Advance" and self.ref_docname: - frappe.db.set_value("Employee Advance", self.ref_docname, "return_amount", self.amount) - + self.update_return_amount_in_employee_advance() self.update_employee_referral() def on_cancel(self): + self.update_return_amount_in_employee_advance() self.update_employee_referral(cancel=True) def validate(self): @@ -98,6 +95,17 @@ class AdditionalSalary(Document): frappe.throw(_("Additional Salary for referral bonus can only be created against Employee Referral with status {0}").format( frappe.bold("Accepted"))) + def update_return_amount_in_employee_advance(self): + if self.ref_doctype == "Employee Advance" and self.ref_docname: + return_amount = frappe.db.get_value("Employee Advance", self.ref_docname, "return_amount") + + if self.docstatus == 2: + return_amount -= self.amount + else: + return_amount += self.amount + + frappe.db.set_value("Employee Advance", self.ref_docname, "return_amount", return_amount) + def update_employee_referral(self, cancel=False): if self.ref_doctype == "Employee Referral": status = "Unpaid" if cancel else "Paid" @@ -115,27 +123,28 @@ class AdditionalSalary(Document): no_of_days = date_diff(getdate(end_date), getdate(start_date)) + 1 return amount_per_day * no_of_days +@frappe.whitelist() def get_additional_salaries(employee, start_date, end_date, component_type): - additional_salary_list = frappe.db.sql(""" - select name, salary_component as component, type, amount, - overwrite_salary_structure_amount as overwrite, - deduct_full_tax_on_selected_payroll_date - from `tabAdditional Salary` - where employee=%(employee)s - and docstatus = 1 - and ( - payroll_date between %(from_date)s and %(to_date)s - or - from_date <= %(to_date)s and to_date >= %(to_date)s - ) - and type = %(component_type)s - order by salary_component, overwrite ASC - """, { - 'employee': employee, - 'from_date': start_date, - 'to_date': end_date, - 'component_type': "Earning" if component_type == "earnings" else "Deduction" - }, as_dict=1) + comp_type = 'Earning' if component_type == 'earnings' else 'Deduction' + + additional_sal = frappe.qb.DocType('Additional Salary') + component_field = additional_sal.salary_component.as_('component') + overwrite_field = additional_sal.overwrite_salary_structure_amount.as_('overwrite') + + additional_salary_list = frappe.qb.from_( + additional_sal + ).select( + additional_sal.name, component_field, additional_sal.type, + additional_sal.amount, additional_sal.is_recurring, overwrite_field, + additional_sal.deduct_full_tax_on_selected_payroll_date + ).where( + (additional_sal.employee == employee) + & (additional_sal.docstatus == 1) + & (additional_sal.type == comp_type) + ).where( + additional_sal.payroll_date[start_date: end_date] + | ((additional_sal.from_date <= end_date) & (additional_sal.to_date >= end_date)) + ).run(as_dict=True) additional_salaries = [] components_to_overwrite = [] diff --git a/erpnext/payroll/doctype/additional_salary/test_additional_salary.py b/erpnext/payroll/doctype/additional_salary/test_additional_salary.py index 2ad4afef251..84de912e431 100644 --- a/erpnext/payroll/doctype/additional_salary/test_additional_salary.py +++ b/erpnext/payroll/doctype/additional_salary/test_additional_salary.py @@ -1,7 +1,5 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2018, Frappe Technologies Pvt. Ltd. and Contributors # See license.txt -from __future__ import unicode_literals import unittest diff --git a/erpnext/payroll/doctype/employee_benefit_application/employee_benefit_application.py b/erpnext/payroll/doctype/employee_benefit_application/employee_benefit_application.py index 9983f012875..eda50150ebd 100644 --- a/erpnext/payroll/doctype/employee_benefit_application/employee_benefit_application.py +++ b/erpnext/payroll/doctype/employee_benefit_application/employee_benefit_application.py @@ -1,8 +1,6 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2018, Frappe Technologies Pvt. Ltd. and contributors # For license information, please see license.txt -from __future__ import unicode_literals import frappe from frappe import _ diff --git a/erpnext/payroll/doctype/employee_benefit_application/test_employee_benefit_application.py b/erpnext/payroll/doctype/employee_benefit_application/test_employee_benefit_application.py index ea05e0e0e05..02149adfce5 100644 --- a/erpnext/payroll/doctype/employee_benefit_application/test_employee_benefit_application.py +++ b/erpnext/payroll/doctype/employee_benefit_application/test_employee_benefit_application.py @@ -1,7 +1,5 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2018, Frappe Technologies Pvt. Ltd. and Contributors # See license.txt -from __future__ import unicode_literals import unittest diff --git a/erpnext/payroll/doctype/employee_benefit_application_detail/employee_benefit_application_detail.py b/erpnext/payroll/doctype/employee_benefit_application_detail/employee_benefit_application_detail.py index ddcbaa20619..51aa2c9dcfc 100644 --- a/erpnext/payroll/doctype/employee_benefit_application_detail/employee_benefit_application_detail.py +++ b/erpnext/payroll/doctype/employee_benefit_application_detail/employee_benefit_application_detail.py @@ -1,8 +1,6 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2020, Frappe Technologies Pvt. Ltd. and contributors # For license information, please see license.txt -from __future__ import unicode_literals # import frappe from frappe.model.document import Document diff --git a/erpnext/payroll/doctype/employee_benefit_claim/employee_benefit_claim.py b/erpnext/payroll/doctype/employee_benefit_claim/employee_benefit_claim.py index 7898e04cf44..801ce4ba367 100644 --- a/erpnext/payroll/doctype/employee_benefit_claim/employee_benefit_claim.py +++ b/erpnext/payroll/doctype/employee_benefit_claim/employee_benefit_claim.py @@ -1,8 +1,6 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2018, Frappe Technologies Pvt. Ltd. and contributors # For license information, please see license.txt -from __future__ import unicode_literals import frappe from frappe import _ diff --git a/erpnext/payroll/doctype/employee_benefit_claim/test_employee_benefit_claim.py b/erpnext/payroll/doctype/employee_benefit_claim/test_employee_benefit_claim.py index f3f2229fb2e..b1d3c66ca86 100644 --- a/erpnext/payroll/doctype/employee_benefit_claim/test_employee_benefit_claim.py +++ b/erpnext/payroll/doctype/employee_benefit_claim/test_employee_benefit_claim.py @@ -1,7 +1,5 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2018, Frappe Technologies Pvt. Ltd. and Contributors # See license.txt -from __future__ import unicode_literals import unittest diff --git a/erpnext/payroll/doctype/employee_incentive/employee_incentive.py b/erpnext/payroll/doctype/employee_incentive/employee_incentive.py index 74d073668d7..a37e22425f7 100644 --- a/erpnext/payroll/doctype/employee_incentive/employee_incentive.py +++ b/erpnext/payroll/doctype/employee_incentive/employee_incentive.py @@ -1,8 +1,6 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2018, Frappe Technologies Pvt. Ltd. and contributors # For license information, please see license.txt -from __future__ import unicode_literals import frappe from frappe import _ diff --git a/erpnext/payroll/doctype/employee_incentive/test_employee_incentive.py b/erpnext/payroll/doctype/employee_incentive/test_employee_incentive.py index 3c95fa80ec0..e296fdf864f 100644 --- a/erpnext/payroll/doctype/employee_incentive/test_employee_incentive.py +++ b/erpnext/payroll/doctype/employee_incentive/test_employee_incentive.py @@ -1,7 +1,5 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2018, Frappe Technologies Pvt. Ltd. and Contributors # See license.txt -from __future__ import unicode_literals import unittest diff --git a/erpnext/payroll/doctype/employee_other_income/employee_other_income.py b/erpnext/payroll/doctype/employee_other_income/employee_other_income.py index 73a0321c8fe..51059a1364a 100644 --- a/erpnext/payroll/doctype/employee_other_income/employee_other_income.py +++ b/erpnext/payroll/doctype/employee_other_income/employee_other_income.py @@ -1,8 +1,6 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2020, Frappe Technologies Pvt. Ltd. and contributors # For license information, please see license.txt -from __future__ import unicode_literals # import frappe from frappe.model.document import Document diff --git a/erpnext/payroll/doctype/employee_other_income/test_employee_other_income.py b/erpnext/payroll/doctype/employee_other_income/test_employee_other_income.py index 5b735b37a16..8f0f6376504 100644 --- a/erpnext/payroll/doctype/employee_other_income/test_employee_other_income.py +++ b/erpnext/payroll/doctype/employee_other_income/test_employee_other_income.py @@ -1,7 +1,5 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2020, Frappe Technologies Pvt. Ltd. and Contributors # See license.txt -from __future__ import unicode_literals # import frappe import unittest diff --git a/erpnext/payroll/doctype/employee_tax_exemption_category/employee_tax_exemption_category.py b/erpnext/payroll/doctype/employee_tax_exemption_category/employee_tax_exemption_category.py index f88f551a2ee..5c109dec965 100644 --- a/erpnext/payroll/doctype/employee_tax_exemption_category/employee_tax_exemption_category.py +++ b/erpnext/payroll/doctype/employee_tax_exemption_category/employee_tax_exemption_category.py @@ -1,8 +1,6 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2018, Frappe Technologies Pvt. Ltd. and contributors # For license information, please see license.txt -from __future__ import unicode_literals from frappe.model.document import Document diff --git a/erpnext/payroll/doctype/employee_tax_exemption_category/test_employee_tax_exemption_category.py b/erpnext/payroll/doctype/employee_tax_exemption_category/test_employee_tax_exemption_category.py index e6bc3abf127..84e6183f3b7 100644 --- a/erpnext/payroll/doctype/employee_tax_exemption_category/test_employee_tax_exemption_category.py +++ b/erpnext/payroll/doctype/employee_tax_exemption_category/test_employee_tax_exemption_category.py @@ -1,7 +1,5 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2018, Frappe Technologies Pvt. Ltd. and Contributors # See license.txt -from __future__ import unicode_literals import unittest diff --git a/erpnext/payroll/doctype/employee_tax_exemption_declaration/employee_tax_exemption_declaration.py b/erpnext/payroll/doctype/employee_tax_exemption_declaration/employee_tax_exemption_declaration.py index 099ab0dcde0..9b5eab636f1 100644 --- a/erpnext/payroll/doctype/employee_tax_exemption_declaration/employee_tax_exemption_declaration.py +++ b/erpnext/payroll/doctype/employee_tax_exemption_declaration/employee_tax_exemption_declaration.py @@ -1,8 +1,6 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2018, Frappe Technologies Pvt. Ltd. and contributors # For license information, please see license.txt -from __future__ import unicode_literals import frappe from frappe.model.document import Document diff --git a/erpnext/payroll/doctype/employee_tax_exemption_declaration/test_employee_tax_exemption_declaration.py b/erpnext/payroll/doctype/employee_tax_exemption_declaration/test_employee_tax_exemption_declaration.py index b7154a4da15..fc28afdc3e5 100644 --- a/erpnext/payroll/doctype/employee_tax_exemption_declaration/test_employee_tax_exemption_declaration.py +++ b/erpnext/payroll/doctype/employee_tax_exemption_declaration/test_employee_tax_exemption_declaration.py @@ -1,7 +1,5 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2018, Frappe Technologies Pvt. Ltd. and Contributors # See license.txt -from __future__ import unicode_literals import unittest diff --git a/erpnext/payroll/doctype/employee_tax_exemption_declaration_category/employee_tax_exemption_declaration_category.py b/erpnext/payroll/doctype/employee_tax_exemption_declaration_category/employee_tax_exemption_declaration_category.py index 2923e57333d..4322f31c015 100644 --- a/erpnext/payroll/doctype/employee_tax_exemption_declaration_category/employee_tax_exemption_declaration_category.py +++ b/erpnext/payroll/doctype/employee_tax_exemption_declaration_category/employee_tax_exemption_declaration_category.py @@ -1,8 +1,6 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2020, Frappe Technologies Pvt. Ltd. and contributors # For license information, please see license.txt -from __future__ import unicode_literals # import frappe from frappe.model.document import Document diff --git a/erpnext/payroll/doctype/employee_tax_exemption_proof_submission/employee_tax_exemption_proof_submission.py b/erpnext/payroll/doctype/employee_tax_exemption_proof_submission/employee_tax_exemption_proof_submission.py index f35fd3caf90..56e73b37dff 100644 --- a/erpnext/payroll/doctype/employee_tax_exemption_proof_submission/employee_tax_exemption_proof_submission.py +++ b/erpnext/payroll/doctype/employee_tax_exemption_proof_submission/employee_tax_exemption_proof_submission.py @@ -1,8 +1,6 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2018, Frappe Technologies Pvt. Ltd. and contributors # For license information, please see license.txt -from __future__ import unicode_literals from frappe.model.document import Document from frappe.utils import flt diff --git a/erpnext/payroll/doctype/employee_tax_exemption_proof_submission/test_employee_tax_exemption_proof_submission.py b/erpnext/payroll/doctype/employee_tax_exemption_proof_submission/test_employee_tax_exemption_proof_submission.py index aafc0a13211..f2aa64c2878 100644 --- a/erpnext/payroll/doctype/employee_tax_exemption_proof_submission/test_employee_tax_exemption_proof_submission.py +++ b/erpnext/payroll/doctype/employee_tax_exemption_proof_submission/test_employee_tax_exemption_proof_submission.py @@ -1,7 +1,5 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2018, Frappe Technologies Pvt. Ltd. and Contributors # See license.txt -from __future__ import unicode_literals import unittest diff --git a/erpnext/payroll/doctype/employee_tax_exemption_proof_submission_detail/employee_tax_exemption_proof_submission_detail.py b/erpnext/payroll/doctype/employee_tax_exemption_proof_submission_detail/employee_tax_exemption_proof_submission_detail.py index e0a11aec162..37209e5840b 100644 --- a/erpnext/payroll/doctype/employee_tax_exemption_proof_submission_detail/employee_tax_exemption_proof_submission_detail.py +++ b/erpnext/payroll/doctype/employee_tax_exemption_proof_submission_detail/employee_tax_exemption_proof_submission_detail.py @@ -1,8 +1,6 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2020, Frappe Technologies Pvt. Ltd. and contributors # For license information, please see license.txt -from __future__ import unicode_literals # import frappe from frappe.model.document import Document diff --git a/erpnext/payroll/doctype/employee_tax_exemption_sub_category/employee_tax_exemption_sub_category.py b/erpnext/payroll/doctype/employee_tax_exemption_sub_category/employee_tax_exemption_sub_category.py index 5948ef208bf..4ac11f7112d 100644 --- a/erpnext/payroll/doctype/employee_tax_exemption_sub_category/employee_tax_exemption_sub_category.py +++ b/erpnext/payroll/doctype/employee_tax_exemption_sub_category/employee_tax_exemption_sub_category.py @@ -1,8 +1,6 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2018, Frappe Technologies Pvt. Ltd. and contributors # For license information, please see license.txt -from __future__ import unicode_literals import frappe from frappe import _ diff --git a/erpnext/payroll/doctype/employee_tax_exemption_sub_category/test_employee_tax_exemption_sub_category.py b/erpnext/payroll/doctype/employee_tax_exemption_sub_category/test_employee_tax_exemption_sub_category.py index 0086086bde6..64d2e3a1e6f 100644 --- a/erpnext/payroll/doctype/employee_tax_exemption_sub_category/test_employee_tax_exemption_sub_category.py +++ b/erpnext/payroll/doctype/employee_tax_exemption_sub_category/test_employee_tax_exemption_sub_category.py @@ -1,7 +1,5 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2018, Frappe Technologies Pvt. Ltd. and Contributors # See license.txt -from __future__ import unicode_literals import unittest diff --git a/erpnext/payroll/doctype/gratuity/gratuity.py b/erpnext/payroll/doctype/gratuity/gratuity.py index cc28dc4972f..f563c08a047 100644 --- a/erpnext/payroll/doctype/gratuity/gratuity.py +++ b/erpnext/payroll/doctype/gratuity/gratuity.py @@ -1,8 +1,6 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2020, Frappe Technologies Pvt. Ltd. and contributors # For license information, please see license.txt -from __future__ import unicode_literals from math import floor diff --git a/erpnext/payroll/doctype/gratuity/gratuity_dashboard.py b/erpnext/payroll/doctype/gratuity/gratuity_dashboard.py index 1599fc2bdef..aeadba186d0 100644 --- a/erpnext/payroll/doctype/gratuity/gratuity_dashboard.py +++ b/erpnext/payroll/doctype/gratuity/gratuity_dashboard.py @@ -1,5 +1,3 @@ -from __future__ import unicode_literals - from frappe import _ diff --git a/erpnext/payroll/doctype/gratuity/test_gratuity.py b/erpnext/payroll/doctype/gratuity/test_gratuity.py index 1403e9b9389..78355cae645 100644 --- a/erpnext/payroll/doctype/gratuity/test_gratuity.py +++ b/erpnext/payroll/doctype/gratuity/test_gratuity.py @@ -1,7 +1,5 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2020, Frappe Technologies Pvt. Ltd. and Contributors # See license.txt -from __future__ import unicode_literals import unittest diff --git a/erpnext/payroll/doctype/gratuity_applicable_component/gratuity_applicable_component.py b/erpnext/payroll/doctype/gratuity_applicable_component/gratuity_applicable_component.py index d76b26d05f6..9c1657d21da 100644 --- a/erpnext/payroll/doctype/gratuity_applicable_component/gratuity_applicable_component.py +++ b/erpnext/payroll/doctype/gratuity_applicable_component/gratuity_applicable_component.py @@ -1,8 +1,6 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2020, Frappe Technologies Pvt. Ltd. and contributors # For license information, please see license.txt -from __future__ import unicode_literals # import frappe from frappe.model.document import Document diff --git a/erpnext/payroll/doctype/gratuity_rule/gratuity_rule.py b/erpnext/payroll/doctype/gratuity_rule/gratuity_rule.py index 95d2929fffa..d30cfc64848 100644 --- a/erpnext/payroll/doctype/gratuity_rule/gratuity_rule.py +++ b/erpnext/payroll/doctype/gratuity_rule/gratuity_rule.py @@ -1,8 +1,6 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2020, Frappe Technologies Pvt. Ltd. and contributors # For license information, please see license.txt -from __future__ import unicode_literals import frappe from frappe import _ diff --git a/erpnext/payroll/doctype/gratuity_rule/gratuity_rule_dashboard.py b/erpnext/payroll/doctype/gratuity_rule/gratuity_rule_dashboard.py index 60dcfa45297..e7c67fbe11b 100644 --- a/erpnext/payroll/doctype/gratuity_rule/gratuity_rule_dashboard.py +++ b/erpnext/payroll/doctype/gratuity_rule/gratuity_rule_dashboard.py @@ -1,5 +1,3 @@ -from __future__ import unicode_literals - from frappe import _ diff --git a/erpnext/payroll/doctype/gratuity_rule/test_gratuity_rule.py b/erpnext/payroll/doctype/gratuity_rule/test_gratuity_rule.py index c81d7b7b9e6..8393050b4a0 100644 --- a/erpnext/payroll/doctype/gratuity_rule/test_gratuity_rule.py +++ b/erpnext/payroll/doctype/gratuity_rule/test_gratuity_rule.py @@ -1,7 +1,5 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2020, Frappe Technologies Pvt. Ltd. and Contributors # See license.txt -from __future__ import unicode_literals # import frappe import unittest diff --git a/erpnext/payroll/doctype/gratuity_rule_slab/gratuity_rule_slab.py b/erpnext/payroll/doctype/gratuity_rule_slab/gratuity_rule_slab.py index dcd7e468655..2ae6b547986 100644 --- a/erpnext/payroll/doctype/gratuity_rule_slab/gratuity_rule_slab.py +++ b/erpnext/payroll/doctype/gratuity_rule_slab/gratuity_rule_slab.py @@ -1,8 +1,6 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2020, Frappe Technologies Pvt. Ltd. and contributors # For license information, please see license.txt -from __future__ import unicode_literals # import frappe from frappe.model.document import Document diff --git a/erpnext/payroll/doctype/income_tax_slab/income_tax_slab.py b/erpnext/payroll/doctype/income_tax_slab/income_tax_slab.py index f778fd90e13..040b2c89353 100644 --- a/erpnext/payroll/doctype/income_tax_slab/income_tax_slab.py +++ b/erpnext/payroll/doctype/income_tax_slab/income_tax_slab.py @@ -1,8 +1,6 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2020, Frappe Technologies Pvt. Ltd. and contributors # For license information, please see license.txt -from __future__ import unicode_literals from frappe.model.document import Document diff --git a/erpnext/payroll/doctype/income_tax_slab/test_income_tax_slab.py b/erpnext/payroll/doctype/income_tax_slab/test_income_tax_slab.py index d76299049de..680cb3bb000 100644 --- a/erpnext/payroll/doctype/income_tax_slab/test_income_tax_slab.py +++ b/erpnext/payroll/doctype/income_tax_slab/test_income_tax_slab.py @@ -1,7 +1,5 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2020, Frappe Technologies Pvt. Ltd. and Contributors # See license.txt -from __future__ import unicode_literals # import frappe import unittest diff --git a/erpnext/payroll/doctype/income_tax_slab_other_charges/income_tax_slab_other_charges.py b/erpnext/payroll/doctype/income_tax_slab_other_charges/income_tax_slab_other_charges.py index 3314677485f..53911a945bd 100644 --- a/erpnext/payroll/doctype/income_tax_slab_other_charges/income_tax_slab_other_charges.py +++ b/erpnext/payroll/doctype/income_tax_slab_other_charges/income_tax_slab_other_charges.py @@ -1,8 +1,6 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2020, Frappe Technologies Pvt. Ltd. and contributors # For license information, please see license.txt -from __future__ import unicode_literals # import frappe from frappe.model.document import Document diff --git a/erpnext/payroll/doctype/payroll_employee_detail/payroll_employee_detail.py b/erpnext/payroll/doctype/payroll_employee_detail/payroll_employee_detail.py index 074d2232245..8cc426b9dba 100644 --- a/erpnext/payroll/doctype/payroll_employee_detail/payroll_employee_detail.py +++ b/erpnext/payroll/doctype/payroll_employee_detail/payroll_employee_detail.py @@ -1,8 +1,6 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2017, Frappe Technologies Pvt. Ltd. and contributors # For license information, please see license.txt -from __future__ import unicode_literals from frappe.model.document import Document diff --git a/erpnext/payroll/doctype/payroll_entry/payroll_entry.py b/erpnext/payroll/doctype/payroll_entry/payroll_entry.py index f1557c78a37..84c59a2c2b8 100644 --- a/erpnext/payroll/doctype/payroll_entry/payroll_entry.py +++ b/erpnext/payroll/doctype/payroll_entry/payroll_entry.py @@ -1,8 +1,6 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2017, Frappe Technologies Pvt. Ltd. and contributors # For license information, please see license.txt -from __future__ import unicode_literals import frappe from dateutil.relativedelta import relativedelta diff --git a/erpnext/payroll/doctype/payroll_entry/payroll_entry_dashboard.py b/erpnext/payroll/doctype/payroll_entry/payroll_entry_dashboard.py index 16e44d08684..a33b28de40f 100644 --- a/erpnext/payroll/doctype/payroll_entry/payroll_entry_dashboard.py +++ b/erpnext/payroll/doctype/payroll_entry/payroll_entry_dashboard.py @@ -1,6 +1,3 @@ -from __future__ import unicode_literals - - def get_data(): return { 'fieldname': 'payroll_entry', diff --git a/erpnext/payroll/doctype/payroll_entry/test_payroll_entry.py b/erpnext/payroll/doctype/payroll_entry/test_payroll_entry.py index dd0e1270800..c6f38972880 100644 --- a/erpnext/payroll/doctype/payroll_entry/test_payroll_entry.py +++ b/erpnext/payroll/doctype/payroll_entry/test_payroll_entry.py @@ -1,6 +1,5 @@ # Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors # License: GNU General Public License v3. See license.txt -from __future__ import unicode_literals import unittest diff --git a/erpnext/payroll/doctype/payroll_period/payroll_period.py b/erpnext/payroll/doctype/payroll_period/payroll_period.py index 0de8d63df73..659ec6de7b6 100644 --- a/erpnext/payroll/doctype/payroll_period/payroll_period.py +++ b/erpnext/payroll/doctype/payroll_period/payroll_period.py @@ -1,8 +1,6 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2018, Frappe Technologies Pvt. Ltd. and contributors # For license information, please see license.txt -from __future__ import unicode_literals import frappe from frappe import _ diff --git a/erpnext/payroll/doctype/payroll_period/payroll_period_dashboard.py b/erpnext/payroll/doctype/payroll_period/payroll_period_dashboard.py index 4105d8ee928..8a3332fa6b8 100644 --- a/erpnext/payroll/doctype/payroll_period/payroll_period_dashboard.py +++ b/erpnext/payroll/doctype/payroll_period/payroll_period_dashboard.py @@ -1,6 +1,3 @@ -from __future__ import unicode_literals - - def get_data(): return { 'fieldname': 'payroll_period', diff --git a/erpnext/payroll/doctype/payroll_period/test_payroll_period.py b/erpnext/payroll/doctype/payroll_period/test_payroll_period.py index e93c0e524de..61967c04bda 100644 --- a/erpnext/payroll/doctype/payroll_period/test_payroll_period.py +++ b/erpnext/payroll/doctype/payroll_period/test_payroll_period.py @@ -1,7 +1,5 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2018, Frappe Technologies Pvt. Ltd. and Contributors # See license.txt -from __future__ import unicode_literals import unittest diff --git a/erpnext/payroll/doctype/payroll_period_date/payroll_period_date.py b/erpnext/payroll/doctype/payroll_period_date/payroll_period_date.py index fa6835da53b..c90a76a829a 100644 --- a/erpnext/payroll/doctype/payroll_period_date/payroll_period_date.py +++ b/erpnext/payroll/doctype/payroll_period_date/payroll_period_date.py @@ -1,8 +1,6 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2020, Frappe Technologies Pvt. Ltd. and contributors # For license information, please see license.txt -from __future__ import unicode_literals # import frappe from frappe.model.document import Document diff --git a/erpnext/payroll/doctype/payroll_settings/payroll_settings.py b/erpnext/payroll/doctype/payroll_settings/payroll_settings.py index b85d5545d04..6fd30946f55 100644 --- a/erpnext/payroll/doctype/payroll_settings/payroll_settings.py +++ b/erpnext/payroll/doctype/payroll_settings/payroll_settings.py @@ -1,8 +1,6 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2020, Frappe Technologies Pvt. Ltd. and contributors # For license information, please see license.txt -from __future__ import unicode_literals import frappe from frappe import _ diff --git a/erpnext/payroll/doctype/payroll_settings/test_payroll_settings.py b/erpnext/payroll/doctype/payroll_settings/test_payroll_settings.py index 30a6a332b7c..3b96db6ed4c 100644 --- a/erpnext/payroll/doctype/payroll_settings/test_payroll_settings.py +++ b/erpnext/payroll/doctype/payroll_settings/test_payroll_settings.py @@ -1,7 +1,5 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2020, Frappe Technologies Pvt. Ltd. and Contributors # See license.txt -from __future__ import unicode_literals # import frappe import unittest diff --git a/erpnext/payroll/doctype/retention_bonus/retention_bonus.py b/erpnext/payroll/doctype/retention_bonus/retention_bonus.py index 7e731e7fce1..10e8381007b 100644 --- a/erpnext/payroll/doctype/retention_bonus/retention_bonus.py +++ b/erpnext/payroll/doctype/retention_bonus/retention_bonus.py @@ -1,8 +1,6 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2018, Frappe Technologies Pvt. Ltd. and contributors # For license information, please see license.txt -from __future__ import unicode_literals import frappe from frappe import _ diff --git a/erpnext/payroll/doctype/retention_bonus/test_retention_bonus.py b/erpnext/payroll/doctype/retention_bonus/test_retention_bonus.py index a380d9fb44a..c86bf335114 100644 --- a/erpnext/payroll/doctype/retention_bonus/test_retention_bonus.py +++ b/erpnext/payroll/doctype/retention_bonus/test_retention_bonus.py @@ -1,7 +1,5 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2018, Frappe Technologies Pvt. Ltd. and Contributors # See license.txt -from __future__ import unicode_literals import unittest diff --git a/erpnext/payroll/doctype/salary_component/salary_component.py b/erpnext/payroll/doctype/salary_component/salary_component.py index 761d4436f37..b8def58643a 100644 --- a/erpnext/payroll/doctype/salary_component/salary_component.py +++ b/erpnext/payroll/doctype/salary_component/salary_component.py @@ -1,8 +1,6 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and contributors # For license information, please see license.txt -from __future__ import unicode_literals from frappe.model.document import Document from frappe.model.naming import append_number_if_name_exists diff --git a/erpnext/payroll/doctype/salary_component/test_salary_component.py b/erpnext/payroll/doctype/salary_component/test_salary_component.py index 939fa4aade1..6e00971a230 100644 --- a/erpnext/payroll/doctype/salary_component/test_salary_component.py +++ b/erpnext/payroll/doctype/salary_component/test_salary_component.py @@ -1,7 +1,5 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors # See license.txt -from __future__ import unicode_literals import unittest diff --git a/erpnext/payroll/doctype/salary_detail/salary_detail.json b/erpnext/payroll/doctype/salary_detail/salary_detail.json index 393f647cc88..665f0a8297e 100644 --- a/erpnext/payroll/doctype/salary_detail/salary_detail.json +++ b/erpnext/payroll/doctype/salary_detail/salary_detail.json @@ -12,6 +12,7 @@ "year_to_date", "section_break_5", "additional_salary", + "is_recurring_additional_salary", "statistical_component", "depends_on_payment_days", "exempted_from_income_tax", @@ -235,11 +236,19 @@ "label": "Year To Date", "options": "currency", "read_only": 1 - } + }, + { + "default": "0", + "depends_on": "eval:doc.parenttype=='Salary Slip' && doc.additional_salary", + "fieldname": "is_recurring_additional_salary", + "fieldtype": "Check", + "label": "Is Recurring Additional Salary", + "read_only": 1 + } ], "istable": 1, "links": [], - "modified": "2021-01-14 13:39:15.847158", + "modified": "2021-08-30 13:39:15.847158", "modified_by": "Administrator", "module": "Payroll", "name": "Salary Detail", diff --git a/erpnext/payroll/doctype/salary_detail/salary_detail.py b/erpnext/payroll/doctype/salary_detail/salary_detail.py index 50d1958caec..c74bd546eb3 100644 --- a/erpnext/payroll/doctype/salary_detail/salary_detail.py +++ b/erpnext/payroll/doctype/salary_detail/salary_detail.py @@ -1,8 +1,6 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and contributors # For license information, please see license.txt -from __future__ import unicode_literals from frappe.model.document import Document diff --git a/erpnext/payroll/doctype/salary_slip/__init__.py b/erpnext/payroll/doctype/salary_slip/__init__.py index baffc488252..e69de29bb2d 100644 --- a/erpnext/payroll/doctype/salary_slip/__init__.py +++ b/erpnext/payroll/doctype/salary_slip/__init__.py @@ -1 +0,0 @@ -from __future__ import unicode_literals diff --git a/erpnext/payroll/doctype/salary_slip/salary_slip.json b/erpnext/payroll/doctype/salary_slip/salary_slip.json index 19744037a54..7a80e69374f 100644 --- a/erpnext/payroll/doctype/salary_slip/salary_slip.json +++ b/erpnext/payroll/doctype/salary_slip/salary_slip.json @@ -329,7 +329,7 @@ { "fieldname": "earning_deduction", "fieldtype": "Section Break", - "label": "Earning & Deduction", + "label": "Earnings & Deductions", "oldfieldtype": "Section Break" }, { @@ -380,7 +380,7 @@ "depends_on": "total_loan_repayment", "fieldname": "loan_repayment", "fieldtype": "Section Break", - "label": "Loan repayment" + "label": "Loan Repayment" }, { "fieldname": "loans", @@ -425,7 +425,7 @@ { "fieldname": "net_pay_info", "fieldtype": "Section Break", - "label": "net pay info" + "label": "Net Pay Info" }, { "fieldname": "net_pay", @@ -647,7 +647,7 @@ "idx": 9, "is_submittable": 1, "links": [], - "modified": "2021-09-01 10:35:52.374549", + "modified": "2021-10-08 11:47:47.098248", "modified_by": "Administrator", "module": "Payroll", "name": "Salary Slip", diff --git a/erpnext/payroll/doctype/salary_slip/salary_slip.py b/erpnext/payroll/doctype/salary_slip/salary_slip.py index 8c48345d8fd..05af09e49db 100644 --- a/erpnext/payroll/doctype/salary_slip/salary_slip.py +++ b/erpnext/payroll/doctype/salary_slip/salary_slip.py @@ -1,7 +1,6 @@ # Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors # License: GNU General Public License v3. See license.txt -from __future__ import unicode_literals import datetime import math @@ -22,7 +21,6 @@ from frappe.utils import ( rounded, ) from frappe.utils.background_jobs import enqueue -from six import iteritems import erpnext from erpnext.accounts.utils import get_fiscal_year @@ -172,7 +170,6 @@ class SalarySlip(TransactionBase): and employee = %s and name != %s {0}""".format(cond), (self.start_date, self.end_date, self.employee, self.name)) if ret_exist: - self.employee = '' frappe.throw(_("Salary Slip of employee {0} already created for this period").format(self.employee)) else: for data in self.timesheets: @@ -487,7 +484,7 @@ class SalarySlip(TransactionBase): self.calculate_component_amounts("deductions") self.set_loan_repayment() - self.set_component_amounts_based_on_payment_days() + self.set_precision_for_component_amounts() self.set_net_pay() def set_net_pay(self): @@ -630,7 +627,8 @@ class SalarySlip(TransactionBase): get_salary_component_data(additional_salary.component), additional_salary.amount, component_type, - additional_salary + additional_salary, + is_recurring = additional_salary.is_recurring ) def add_tax_components(self, payroll_period): @@ -651,7 +649,7 @@ class SalarySlip(TransactionBase): tax_row = get_salary_component_data(d) self.update_component_row(tax_row, tax_amount, "deductions") - def update_component_row(self, component_data, amount, component_type, additional_salary=None): + def update_component_row(self, component_data, amount, component_type, additional_salary=None, is_recurring = 0): component_row = None for d in self.get(component_type): if d.salary_component != component_data.salary_component: @@ -698,6 +696,8 @@ class SalarySlip(TransactionBase): else: component_row.default_amount = 0 component_row.additional_amount = amount + + component_row.is_recurring_additional_salary = is_recurring component_row.additional_salary = additional_salary.name component_row.deduct_full_tax_on_selected_payroll_date = \ additional_salary.deduct_full_tax_on_selected_payroll_date @@ -709,6 +709,17 @@ class SalarySlip(TransactionBase): component_row.amount = amount + self.update_component_amount_based_on_payment_days(component_row) + + def update_component_amount_based_on_payment_days(self, component_row): + joining_date, relieving_date = self.get_joining_and_relieving_dates() + component_row.amount = self.get_amount_based_on_payment_days(component_row, joining_date, relieving_date)[0] + + def set_precision_for_component_amounts(self): + for component_type in ("earnings", "deductions"): + for component_row in self.get(component_type): + component_row.amount = flt(component_row.amount, component_row.precision("amount")) + def calculate_variable_based_on_taxable_salary(self, tax_component, payroll_period): if not payroll_period: frappe.msgprint(_("Start and end dates not in a valid Payroll Period, cannot calculate {0}.") @@ -866,14 +877,7 @@ class SalarySlip(TransactionBase): return total_tax_paid def get_taxable_earnings(self, allow_tax_exemption=False, based_on_payment_days=0): - joining_date, relieving_date = frappe.get_cached_value("Employee", self.employee, - ["date_of_joining", "relieving_date"]) - - if not relieving_date: - relieving_date = getdate(self.end_date) - - if not joining_date: - frappe.throw(_("Please set the Date Of Joining for employee {0}").format(frappe.bold(self.employee_name))) + joining_date, relieving_date = self.get_joining_and_relieving_dates() taxable_earnings = 0 additional_income = 0 @@ -884,28 +888,39 @@ class SalarySlip(TransactionBase): if based_on_payment_days: amount, additional_amount = self.get_amount_based_on_payment_days(earning, joining_date, relieving_date) else: - amount, additional_amount = earning.amount, earning.additional_amount + if earning.additional_amount: + amount, additional_amount = earning.amount, earning.additional_amount + else: + amount, additional_amount = earning.default_amount, earning.additional_amount if earning.is_tax_applicable: - if additional_amount: - taxable_earnings += (amount - additional_amount) - additional_income += additional_amount - if earning.deduct_full_tax_on_selected_payroll_date: - additional_income_with_full_tax += additional_amount - continue - if earning.is_flexible_benefit: flexi_benefits += amount else: - taxable_earnings += amount + taxable_earnings += (amount - additional_amount) + additional_income += additional_amount + + # Get additional amount based on future recurring additional salary + if additional_amount and earning.is_recurring_additional_salary: + additional_income += self.get_future_recurring_additional_amount(earning.additional_salary, + earning.additional_amount) # Used earning.additional_amount to consider the amount for the full month + + if earning.deduct_full_tax_on_selected_payroll_date: + additional_income_with_full_tax += additional_amount if allow_tax_exemption: for ded in self.deductions: if ded.exempted_from_income_tax: - amount = ded.amount + amount, additional_amount = ded.amount, ded.additional_amount if based_on_payment_days: - amount = self.get_amount_based_on_payment_days(ded, joining_date, relieving_date)[0] - taxable_earnings -= flt(amount) + amount, additional_amount = self.get_amount_based_on_payment_days(ded, joining_date, relieving_date) + + taxable_earnings -= flt(amount - additional_amount) + additional_income -= additional_amount + + if additional_amount and ded.is_recurring_additional_salary: + additional_income -= self.get_future_recurring_additional_amount(ded.additional_salary, + ded.additional_amount) # Used ded.additional_amount to consider the amount for the full month return frappe._dict({ "taxable_earnings": taxable_earnings, @@ -914,11 +929,21 @@ class SalarySlip(TransactionBase): "flexi_benefits": flexi_benefits }) + def get_future_recurring_additional_amount(self, additional_salary, monthly_additional_amount): + future_recurring_additional_amount = 0 + to_date = frappe.db.get_value("Additional Salary", additional_salary, 'to_date') + # future month count excluding current + future_recurring_period = (getdate(to_date).month - getdate(self.start_date).month) + if future_recurring_period > 0: + future_recurring_additional_amount = monthly_additional_amount * future_recurring_period # Used earning.additional_amount to consider the amount for the full month + return future_recurring_additional_amount + def get_amount_based_on_payment_days(self, row, joining_date, relieving_date): amount, additional_amount = row.amount, row.additional_amount if (self.salary_structure and - cint(row.depends_on_payment_days) and cint(self.total_working_days) and - (not self.salary_slip_based_on_timesheet or + cint(row.depends_on_payment_days) and cint(self.total_working_days) + and not (row.additional_salary and row.default_amount) # to identify overwritten additional salary + and (not self.salary_slip_based_on_timesheet or getdate(self.start_date) < joining_date or (relieving_date and getdate(self.end_date) > relieving_date) )): @@ -1055,7 +1080,7 @@ class SalarySlip(TransactionBase): total += amount return total - def set_component_amounts_based_on_payment_days(self): + def get_joining_and_relieving_dates(self): joining_date, relieving_date = frappe.get_cached_value("Employee", self.employee, ["date_of_joining", "relieving_date"]) @@ -1065,9 +1090,7 @@ class SalarySlip(TransactionBase): if not joining_date: frappe.throw(_("Please set the Date Of Joining for employee {0}").format(frappe.bold(self.employee_name))) - for component_type in ("earnings", "deductions"): - for d in self.get(component_type): - d.amount = flt(self.get_amount_based_on_payment_days(d, joining_date, relieving_date)[0], d.precision("amount")) + return joining_date, relieving_date def set_loan_repayment(self): self.total_loan_repayment = 0 @@ -1239,7 +1262,7 @@ class SalarySlip(TransactionBase): salary_slip_sum = frappe.get_list('Salary Slip', fields = ['sum(net_pay) as net_sum', 'sum(gross_pay) as gross_sum'], - filters = {'employee_name' : self.employee_name, + filters = {'employee' : self.employee, 'start_date' : ['>=', period_start_date], 'end_date' : ['<', period_end_date], 'name': ['!=', self.name], @@ -1259,7 +1282,7 @@ class SalarySlip(TransactionBase): first_day_of_the_month = get_first_day(self.start_date) salary_slip_sum = frappe.get_list('Salary Slip', fields = ['sum(net_pay) as sum'], - filters = {'employee_name' : self.employee_name, + filters = {'employee' : self.employee, 'start_date' : ['>=', first_day_of_the_month], 'end_date' : ['<', self.start_date], 'name': ['!=', self.name], @@ -1283,13 +1306,13 @@ class SalarySlip(TransactionBase): INNER JOIN `tabSalary Slip` as salary_slip ON detail.parent = salary_slip.name WHERE - salary_slip.employee_name = %(employee_name)s + salary_slip.employee = %(employee)s AND detail.salary_component = %(component)s AND salary_slip.start_date >= %(period_start_date)s AND salary_slip.end_date < %(period_end_date)s AND salary_slip.name != %(docname)s AND salary_slip.docstatus = 1""", - {'employee_name': self.employee_name, 'component': component.salary_component, 'period_start_date': period_start_date, + {'employee': self.employee, 'component': component.salary_component, 'period_start_date': period_start_date, 'period_end_date': period_end_date, 'docname': self.name} ) @@ -1318,7 +1341,7 @@ class SalarySlip(TransactionBase): from erpnext.hr.doctype.leave_application.leave_application import get_leave_details leave_details = get_leave_details(self.employee, self.end_date) - for leave_type, leave_values in iteritems(leave_details['leave_allocation']): + for leave_type, leave_values in leave_details['leave_allocation'].items(): self.append('leave_details', { 'leave_type': leave_type, 'total_allocated_leaves': flt(leave_values.get('total_leaves')), diff --git a/erpnext/payroll/doctype/salary_slip/test_salary_slip.py b/erpnext/payroll/doctype/salary_slip/test_salary_slip.py index 480daa25954..e4618c31f20 100644 --- a/erpnext/payroll/doctype/salary_slip/test_salary_slip.py +++ b/erpnext/payroll/doctype/salary_slip/test_salary_slip.py @@ -1,6 +1,5 @@ # Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors # License: GNU General Public License v3. See license.txt -from __future__ import unicode_literals import calendar import random @@ -17,6 +16,7 @@ from frappe.utils import ( getdate, nowdate, ) +from frappe.utils.make_random import get_random import erpnext from erpnext.accounts.utils import get_fiscal_year @@ -134,6 +134,59 @@ class TestSalarySlip(unittest.TestCase): frappe.db.set_value("Payroll Settings", None, "payroll_based_on", "Leave") + def test_component_amount_dependent_on_another_payment_days_based_component(self): + from erpnext.hr.doctype.attendance.attendance import mark_attendance + from erpnext.payroll.doctype.salary_structure.test_salary_structure import ( + create_salary_structure_assignment, + ) + + # Payroll based on attendance + frappe.db.set_value("Payroll Settings", None, "payroll_based_on", "Attendance") + + salary_structure = make_salary_structure_for_payment_days_based_component_dependency() + employee = make_employee("test_payment_days_based_component@salary.com", company="_Test Company") + + # base = 50000 + create_salary_structure_assignment(employee, salary_structure.name, company="_Test Company", currency="INR") + + # mark employee absent for a day since this case works fine if payment days are equal to working days + month_start_date = get_first_day(nowdate()) + month_end_date = get_last_day(nowdate()) + + first_sunday = frappe.db.sql(""" + select holiday_date from `tabHoliday` + where parent = 'Salary Slip Test Holiday List' + and holiday_date between %s and %s + order by holiday_date + """, (month_start_date, month_end_date))[0][0] + + mark_attendance(employee, add_days(first_sunday, 1), 'Absent', ignore_validate=True) # counted as absent + + # make salary slip and assert payment days + ss = make_salary_slip_for_payment_days_dependency_test("test_payment_days_based_component@salary.com", salary_structure.name) + self.assertEqual(ss.absent_days, 1) + + ss.reload() + payment_days_based_comp_amount = 0 + for component in ss.earnings: + if component.salary_component == "HRA - Payment Days": + payment_days_based_comp_amount = flt(component.amount, component.precision("amount")) + break + + # check if the dependent component is calculated using the amount updated after payment days + actual_amount = 0 + precision = 0 + for component in ss.deductions: + if component.salary_component == "P - Employee Provident Fund": + precision = component.precision("amount") + actual_amount = flt(component.amount, precision) + break + + expected_amount = flt((flt(ss.gross_pay) - payment_days_based_comp_amount) * 0.12, precision) + + self.assertEqual(actual_amount, expected_amount) + frappe.db.set_value("Payroll Settings", None, "payroll_based_on", "Leave") + def test_salary_slip_with_holidays_included(self): no_of_days = self.get_no_of_days() frappe.db.set_value("Payroll Settings", None, "include_holidays_in_total_working_days", 1) @@ -482,6 +535,61 @@ class TestSalarySlip(unittest.TestCase): # undelete fixture data frappe.db.rollback() + def test_tax_for_recurring_additional_salary(self): + frappe.db.sql("""delete from `tabPayroll Period`""") + frappe.db.sql("""delete from `tabSalary Component`""") + + payroll_period = create_payroll_period() + + create_tax_slab(payroll_period, allow_tax_exemption=True) + + employee = make_employee("test_tax@salary.slip") + delete_docs = [ + "Salary Slip", + "Additional Salary", + "Employee Tax Exemption Declaration", + "Employee Tax Exemption Proof Submission", + "Employee Benefit Claim", + "Salary Structure Assignment" + ] + for doc in delete_docs: + frappe.db.sql("delete from `tab%s` where employee='%s'" % (doc, employee)) + + from erpnext.payroll.doctype.salary_structure.test_salary_structure import make_salary_structure + + salary_structure = make_salary_structure("Stucture to test tax", "Monthly", + other_details={"max_benefits": 100000}, test_tax=True, + employee=employee, payroll_period=payroll_period) + + + create_salary_slips_for_payroll_period(employee, salary_structure.name, + payroll_period, deduct_random=False, num=3) + + tax_paid = get_tax_paid_in_period(employee) + + annual_tax = 23196.0 + self.assertEqual(tax_paid, annual_tax) + + frappe.db.sql("""delete from `tabSalary Slip` where employee=%s""", (employee)) + + #------------------------------------ + # Recurring additional salary + start_date = add_months(payroll_period.start_date, 3) + end_date = add_months(payroll_period.start_date, 5) + create_recurring_additional_salary(employee, "Performance Bonus", 20000, start_date, end_date) + + frappe.db.sql("""delete from `tabSalary Slip` where employee=%s""", (employee)) + + create_salary_slips_for_payroll_period(employee, salary_structure.name, + payroll_period, deduct_random=False, num=4) + + tax_paid = get_tax_paid_in_period(employee) + + annual_tax = 32315.0 + self.assertEqual(tax_paid, annual_tax) + + frappe.db.rollback() + def make_activity_for_employee(self): activity_type = frappe.get_doc("Activity Type", "_Test Activity Type") activity_type.billing_rate = 50 @@ -864,3 +972,106 @@ def make_holiday_list(): holiday_list = holiday_list.name return holiday_list + +def make_salary_structure_for_payment_days_based_component_dependency(): + earnings = [ + { + "salary_component": "Basic Salary - Payment Days", + "abbr": "P_BS", + "type": "Earning", + "formula": "base", + "amount_based_on_formula": 1 + }, + { + "salary_component": "HRA - Payment Days", + "abbr": "P_HRA", + "type": "Earning", + "depends_on_payment_days": 1, + "amount_based_on_formula": 1, + "formula": "base * 0.20" + } + ] + + make_salary_component(earnings, False, company_list=["_Test Company"]) + + deductions = [ + { + "salary_component": "P - Professional Tax", + "abbr": "P_PT", + "type": "Deduction", + "depends_on_payment_days": 1, + "amount": 200.00 + }, + { + "salary_component": "P - Employee Provident Fund", + "abbr": "P_EPF", + "type": "Deduction", + "exempted_from_income_tax": 1, + "amount_based_on_formula": 1, + "depends_on_payment_days": 0, + "formula": "(gross_pay - P_HRA) * 0.12" + } + ] + + make_salary_component(deductions, False, company_list=["_Test Company"]) + + salary_structure = "Salary Structure with PF" + if frappe.db.exists("Salary Structure", salary_structure): + frappe.db.delete("Salary Structure", salary_structure) + + details = { + "doctype": "Salary Structure", + "name": salary_structure, + "company": "_Test Company", + "payroll_frequency": "Monthly", + "payment_account": get_random("Account", filters={"account_currency": "INR"}), + "currency": "INR" + } + + salary_structure_doc = frappe.get_doc(details) + + for entry in earnings: + salary_structure_doc.append("earnings", entry) + + for entry in deductions: + salary_structure_doc.append("deductions", entry) + + salary_structure_doc.insert() + salary_structure_doc.submit() + + return salary_structure_doc + +def make_salary_slip_for_payment_days_dependency_test(employee, salary_structure): + employee = frappe.db.get_value( + "Employee", + {"user_id": employee}, + ["name", "company", "employee_name"], + as_dict=True + ) + + salary_slip_name = frappe.db.get_value("Salary Slip", {"employee": employee.name}) + + if not salary_slip_name: + salary_slip = make_salary_slip(salary_structure, employee=employee.name) + salary_slip.employee_name = employee.employee_name + salary_slip.payroll_frequency = "Monthly" + salary_slip.posting_date = nowdate() + salary_slip.insert() + else: + salary_slip = frappe.get_doc("Salary Slip", salary_slip_name) + + return salary_slip + +def create_recurring_additional_salary(employee, salary_component, amount, from_date, to_date, company=None): + frappe.get_doc({ + "doctype": "Additional Salary", + "employee": employee, + "company": company or erpnext.get_default_company(), + "salary_component": salary_component, + "is_recurring": 1, + "from_date": from_date, + "to_date": to_date, + "amount": amount, + "type": "Earning", + "currency": erpnext.get_default_currency() + }).submit() diff --git a/erpnext/payroll/doctype/salary_slip_leave/salary_slip_leave.py b/erpnext/payroll/doctype/salary_slip_leave/salary_slip_leave.py index fc8282b82ba..b29a60bd4a8 100644 --- a/erpnext/payroll/doctype/salary_slip_leave/salary_slip_leave.py +++ b/erpnext/payroll/doctype/salary_slip_leave/salary_slip_leave.py @@ -1,8 +1,6 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2021, Frappe Technologies Pvt. Ltd. and contributors # For license information, please see license.txt -from __future__ import unicode_literals # import frappe from frappe.model.document import Document diff --git a/erpnext/payroll/doctype/salary_slip_timesheet/salary_slip_timesheet.py b/erpnext/payroll/doctype/salary_slip_timesheet/salary_slip_timesheet.py index 79c4c6e5715..022eba05fdd 100644 --- a/erpnext/payroll/doctype/salary_slip_timesheet/salary_slip_timesheet.py +++ b/erpnext/payroll/doctype/salary_slip_timesheet/salary_slip_timesheet.py @@ -1,8 +1,6 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2020, Frappe Technologies Pvt. Ltd. and contributors # For license information, please see license.txt -from __future__ import unicode_literals # import frappe from frappe.model.document import Document diff --git a/erpnext/payroll/doctype/salary_structure/__init__.py b/erpnext/payroll/doctype/salary_structure/__init__.py index baffc488252..e69de29bb2d 100644 --- a/erpnext/payroll/doctype/salary_structure/__init__.py +++ b/erpnext/payroll/doctype/salary_structure/__init__.py @@ -1 +0,0 @@ -from __future__ import unicode_literals diff --git a/erpnext/payroll/doctype/salary_structure/salary_structure.py b/erpnext/payroll/doctype/salary_structure/salary_structure.py index ef401b2d1a7..ae83c046a5e 100644 --- a/erpnext/payroll/doctype/salary_structure/salary_structure.py +++ b/erpnext/payroll/doctype/salary_structure/salary_structure.py @@ -1,7 +1,6 @@ # Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors # License: GNU General Public License v3. See license.txt -from __future__ import unicode_literals import frappe from frappe import _ diff --git a/erpnext/payroll/doctype/salary_structure/salary_structure_dashboard.py b/erpnext/payroll/doctype/salary_structure/salary_structure_dashboard.py index 11d9a944096..014d0bab12a 100644 --- a/erpnext/payroll/doctype/salary_structure/salary_structure_dashboard.py +++ b/erpnext/payroll/doctype/salary_structure/salary_structure_dashboard.py @@ -1,6 +1,3 @@ -from __future__ import unicode_literals - - def get_data(): return { 'fieldname': 'salary_structure', diff --git a/erpnext/payroll/doctype/salary_structure/test_salary_structure.py b/erpnext/payroll/doctype/salary_structure/test_salary_structure.py index ff4a55e29cf..e2d0d1c864c 100644 --- a/erpnext/payroll/doctype/salary_structure/test_salary_structure.py +++ b/erpnext/payroll/doctype/salary_structure/test_salary_structure.py @@ -1,6 +1,5 @@ # Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors and Contributors # See license.txt -from __future__ import unicode_literals import unittest diff --git a/erpnext/payroll/doctype/salary_structure_assignment/salary_structure_assignment.py b/erpnext/payroll/doctype/salary_structure_assignment/salary_structure_assignment.py index 385cf36b7f5..e1ff9ca9f04 100644 --- a/erpnext/payroll/doctype/salary_structure_assignment/salary_structure_assignment.py +++ b/erpnext/payroll/doctype/salary_structure_assignment/salary_structure_assignment.py @@ -1,8 +1,6 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2018, Frappe Technologies Pvt. Ltd. and contributors # For license information, please see license.txt -from __future__ import unicode_literals import frappe from frappe import _ diff --git a/erpnext/payroll/doctype/salary_structure_assignment/test_salary_structure_assignment.py b/erpnext/payroll/doctype/salary_structure_assignment/test_salary_structure_assignment.py index fbb894c43ed..56dd0d0fe50 100644 --- a/erpnext/payroll/doctype/salary_structure_assignment/test_salary_structure_assignment.py +++ b/erpnext/payroll/doctype/salary_structure_assignment/test_salary_structure_assignment.py @@ -1,7 +1,5 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2018, Frappe Technologies Pvt. Ltd. and Contributors # See license.txt -from __future__ import unicode_literals import unittest diff --git a/erpnext/payroll/doctype/taxable_salary_slab/taxable_salary_slab.py b/erpnext/payroll/doctype/taxable_salary_slab/taxable_salary_slab.py index c0827c445db..d1ccbe38582 100644 --- a/erpnext/payroll/doctype/taxable_salary_slab/taxable_salary_slab.py +++ b/erpnext/payroll/doctype/taxable_salary_slab/taxable_salary_slab.py @@ -1,8 +1,6 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2020, Frappe Technologies Pvt. Ltd. and contributors # For license information, please see license.txt -from __future__ import unicode_literals # import frappe from frappe.model.document import Document diff --git a/erpnext/payroll/notification/retention_bonus/retention_bonus.py b/erpnext/payroll/notification/retention_bonus/retention_bonus.py index f57de916dd1..02e3e933330 100644 --- a/erpnext/payroll/notification/retention_bonus/retention_bonus.py +++ b/erpnext/payroll/notification/retention_bonus/retention_bonus.py @@ -1,6 +1,3 @@ -from __future__ import unicode_literals - - def get_context(context): # do your magic here pass diff --git a/erpnext/payroll/report/bank_remittance/bank_remittance.py b/erpnext/payroll/report/bank_remittance/bank_remittance.py index d55317e71e4..6c3bd37b043 100644 --- a/erpnext/payroll/report/bank_remittance/bank_remittance.py +++ b/erpnext/payroll/report/bank_remittance/bank_remittance.py @@ -1,7 +1,6 @@ # Copyright (c) 2013, Frappe Technologies Pvt. Ltd. and contributors # For license information, please see license.txt -from __future__ import unicode_literals import frappe from frappe import _, get_all diff --git a/erpnext/payroll/report/income_tax_deductions/income_tax_deductions.py b/erpnext/payroll/report/income_tax_deductions/income_tax_deductions.py index 296a7c233f3..75a9f97ea58 100644 --- a/erpnext/payroll/report/income_tax_deductions/income_tax_deductions.py +++ b/erpnext/payroll/report/income_tax_deductions/income_tax_deductions.py @@ -1,7 +1,6 @@ # Copyright (c) 2013, Frappe Technologies Pvt. Ltd. and contributors # For license information, please see license.txt -from __future__ import unicode_literals import frappe from frappe import _ diff --git a/erpnext/payroll/report/salary_payments_based_on_payment_mode/salary_payments_based_on_payment_mode.py b/erpnext/payroll/report/salary_payments_based_on_payment_mode/salary_payments_based_on_payment_mode.py index 57ea1b3c283..fa68575e688 100644 --- a/erpnext/payroll/report/salary_payments_based_on_payment_mode/salary_payments_based_on_payment_mode.py +++ b/erpnext/payroll/report/salary_payments_based_on_payment_mode/salary_payments_based_on_payment_mode.py @@ -1,7 +1,6 @@ # Copyright (c) 2013, Frappe Technologies Pvt. Ltd. and contributors # For license information, please see license.txt -from __future__ import unicode_literals import frappe from frappe import _ diff --git a/erpnext/payroll/report/salary_payments_via_ecs/salary_payments_via_ecs.py b/erpnext/payroll/report/salary_payments_via_ecs/salary_payments_via_ecs.py index bc8fd9d40b2..578c8164009 100644 --- a/erpnext/payroll/report/salary_payments_via_ecs/salary_payments_via_ecs.py +++ b/erpnext/payroll/report/salary_payments_via_ecs/salary_payments_via_ecs.py @@ -1,7 +1,6 @@ # Copyright (c) 2013, Frappe Technologies Pvt. Ltd. and contributors # For license information, please see license.txt -from __future__ import unicode_literals import frappe from frappe import _ diff --git a/erpnext/payroll/report/salary_register/salary_register.py b/erpnext/payroll/report/salary_register/salary_register.py index 2a9dad66e25..78deb227783 100644 --- a/erpnext/payroll/report/salary_register/salary_register.py +++ b/erpnext/payroll/report/salary_register/salary_register.py @@ -1,7 +1,6 @@ # Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors # License: GNU General Public License v3. See license.txt -from __future__ import unicode_literals import frappe from frappe import _ @@ -135,11 +134,11 @@ def get_ss_earning_map(salary_slips, currency, company_currency): ss_earning_map = {} for d in ss_earnings: - ss_earning_map.setdefault(d.parent, frappe._dict()).setdefault(d.salary_component, []) + ss_earning_map.setdefault(d.parent, frappe._dict()).setdefault(d.salary_component, 0.0) if currency == company_currency: - ss_earning_map[d.parent][d.salary_component] = flt(d.amount) * flt(d.exchange_rate if d.exchange_rate else 1) + ss_earning_map[d.parent][d.salary_component] += flt(d.amount) * flt(d.exchange_rate if d.exchange_rate else 1) else: - ss_earning_map[d.parent][d.salary_component] = flt(d.amount) + ss_earning_map[d.parent][d.salary_component] += flt(d.amount) return ss_earning_map @@ -150,10 +149,10 @@ def get_ss_ded_map(salary_slips, currency, company_currency): ss_ded_map = {} for d in ss_deductions: - ss_ded_map.setdefault(d.parent, frappe._dict()).setdefault(d.salary_component, []) + ss_ded_map.setdefault(d.parent, frappe._dict()).setdefault(d.salary_component, 0.0) if currency == company_currency: - ss_ded_map[d.parent][d.salary_component] = flt(d.amount) * flt(d.exchange_rate if d.exchange_rate else 1) + ss_ded_map[d.parent][d.salary_component] += flt(d.amount) * flt(d.exchange_rate if d.exchange_rate else 1) else: - ss_ded_map[d.parent][d.salary_component] = flt(d.amount) + ss_ded_map[d.parent][d.salary_component] += flt(d.amount) return ss_ded_map diff --git a/erpnext/payroll/workspace/payroll/payroll.json b/erpnext/payroll/workspace/payroll/payroll.json index b55bdc77112..7246dae5bc9 100644 --- a/erpnext/payroll/workspace/payroll/payroll.json +++ b/erpnext/payroll/workspace/payroll/payroll.json @@ -1,5 +1,4 @@ { - "category": "", "charts": [ { "chart_name": "Outgoing Salary", @@ -8,18 +7,12 @@ ], "content": "[{\"type\": \"onboarding\", \"data\": {\"onboarding_name\":\"Payroll\", \"col\": 12}}, {\"type\": \"chart\", \"data\": {\"chart_name\": \"Outgoing Salary\", \"col\": 12}}, {\"type\": \"spacer\", \"data\": {\"col\": 12}}, {\"type\": \"header\", \"data\": {\"text\": \"Your Shortcuts\", \"level\": 4, \"col\": 12}}, {\"type\": \"shortcut\", \"data\": {\"shortcut_name\": \"Salary Structure\", \"col\": 4}}, {\"type\": \"shortcut\", \"data\": {\"shortcut_name\": \"Payroll Entry\", \"col\": 4}}, {\"type\": \"shortcut\", \"data\": {\"shortcut_name\": \"Salary Slip\", \"col\": 4}}, {\"type\": \"shortcut\", \"data\": {\"shortcut_name\": \"Income Tax Slab\", \"col\": 4}}, {\"type\": \"shortcut\", \"data\": {\"shortcut_name\": \"Salary Register\", \"col\": 4}}, {\"type\": \"shortcut\", \"data\": {\"shortcut_name\": \"Dashboard\", \"col\": 4}}, {\"type\": \"spacer\", \"data\": {\"col\": 12}}, {\"type\": \"header\", \"data\": {\"text\": \"Reports & Masters\", \"level\": 4, \"col\": 12}}, {\"type\": \"card\", \"data\": {\"card_name\": \"Payroll\", \"col\": 4}}, {\"type\": \"card\", \"data\": {\"card_name\": \"Taxation\", \"col\": 4}}, {\"type\": \"card\", \"data\": {\"card_name\": \"Compensations\", \"col\": 4}}, {\"type\": \"card\", \"data\": {\"card_name\": \"Reports\", \"col\": 4}}]", "creation": "2020-05-27 19:54:23.405607", - "developer_mode_only": 0, - "disable_user_customization": 0, "docstatus": 0, "doctype": "Workspace", - "extends": "", - "extends_another_page": 0, "for_user": "", "hide_custom": 0, "icon": "money-coins-1", "idx": 0, - "is_default": 0, - "is_standard": 0, "label": "Payroll", "links": [ { @@ -319,15 +312,12 @@ "type": "Link" } ], - "modified": "2021-08-05 12:16:01.335324", + "modified": "2021-08-05 12:16:01.335325", "modified_by": "Administrator", "module": "Payroll", "name": "Payroll", - "onboarding": "Payroll", "owner": "Administrator", "parent_page": "", - "pin_to_bottom": 0, - "pin_to_top": 0, "public": 1, "restrict_to_domain": "", "roles": [], diff --git a/erpnext/portal/doctype/homepage/homepage.py b/erpnext/portal/doctype/homepage/homepage.py index 7eeaf4b80a0..1e056a6dacb 100644 --- a/erpnext/portal/doctype/homepage/homepage.py +++ b/erpnext/portal/doctype/homepage/homepage.py @@ -1,8 +1,6 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and contributors # For license information, please see license.txt -from __future__ import unicode_literals import frappe from frappe.model.document import Document diff --git a/erpnext/portal/doctype/homepage/test_homepage.py b/erpnext/portal/doctype/homepage/test_homepage.py index bc8a8282472..fb0367f9031 100644 --- a/erpnext/portal/doctype/homepage/test_homepage.py +++ b/erpnext/portal/doctype/homepage/test_homepage.py @@ -1,7 +1,5 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2019, Frappe Technologies Pvt. Ltd. and Contributors # See license.txt -from __future__ import unicode_literals import unittest diff --git a/erpnext/portal/doctype/homepage_featured_product/homepage_featured_product.py b/erpnext/portal/doctype/homepage_featured_product/homepage_featured_product.py index 8e8f77605e6..c21461d631d 100644 --- a/erpnext/portal/doctype/homepage_featured_product/homepage_featured_product.py +++ b/erpnext/portal/doctype/homepage_featured_product/homepage_featured_product.py @@ -1,8 +1,6 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and contributors # For license information, please see license.txt -from __future__ import unicode_literals from frappe.model.document import Document diff --git a/erpnext/portal/doctype/homepage_section/homepage_section.py b/erpnext/portal/doctype/homepage_section/homepage_section.py index 081786126e7..7181affbea7 100644 --- a/erpnext/portal/doctype/homepage_section/homepage_section.py +++ b/erpnext/portal/doctype/homepage_section/homepage_section.py @@ -1,8 +1,6 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2019, Frappe Technologies Pvt. Ltd. and contributors # For license information, please see license.txt -from __future__ import unicode_literals from frappe.model.document import Document from frappe.utils import cint diff --git a/erpnext/portal/doctype/homepage_section/test_homepage_section.py b/erpnext/portal/doctype/homepage_section/test_homepage_section.py index 6fb7d0a6f07..b30d983adc3 100644 --- a/erpnext/portal/doctype/homepage_section/test_homepage_section.py +++ b/erpnext/portal/doctype/homepage_section/test_homepage_section.py @@ -1,7 +1,5 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2019, Frappe Technologies Pvt. Ltd. and Contributors # See license.txt -from __future__ import unicode_literals import unittest diff --git a/erpnext/portal/doctype/homepage_section_card/homepage_section_card.py b/erpnext/portal/doctype/homepage_section_card/homepage_section_card.py index b71045207cc..eeff63c3f35 100644 --- a/erpnext/portal/doctype/homepage_section_card/homepage_section_card.py +++ b/erpnext/portal/doctype/homepage_section_card/homepage_section_card.py @@ -1,8 +1,6 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2019, Frappe Technologies Pvt. Ltd. and contributors # For license information, please see license.txt -from __future__ import unicode_literals from frappe.model.document import Document diff --git a/erpnext/portal/doctype/products_settings/products_settings.py b/erpnext/portal/doctype/products_settings/products_settings.py index d4f09b9c8c2..0e106c634b8 100644 --- a/erpnext/portal/doctype/products_settings/products_settings.py +++ b/erpnext/portal/doctype/products_settings/products_settings.py @@ -1,8 +1,6 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and contributors # For license information, please see license.txt -from __future__ import unicode_literals import frappe from frappe import _ diff --git a/erpnext/portal/doctype/products_settings/test_products_settings.py b/erpnext/portal/doctype/products_settings/test_products_settings.py index 5495cc9d961..66026fc0467 100644 --- a/erpnext/portal/doctype/products_settings/test_products_settings.py +++ b/erpnext/portal/doctype/products_settings/test_products_settings.py @@ -1,7 +1,5 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2017, Frappe Technologies Pvt. Ltd. and Contributors # See license.txt -from __future__ import unicode_literals import unittest diff --git a/erpnext/portal/doctype/website_attribute/website_attribute.py b/erpnext/portal/doctype/website_attribute/website_attribute.py index f9ba733b85d..58a73768be2 100644 --- a/erpnext/portal/doctype/website_attribute/website_attribute.py +++ b/erpnext/portal/doctype/website_attribute/website_attribute.py @@ -1,8 +1,6 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2019, Frappe Technologies Pvt. Ltd. and contributors # For license information, please see license.txt -from __future__ import unicode_literals from frappe.model.document import Document diff --git a/erpnext/portal/doctype/website_filter_field/website_filter_field.py b/erpnext/portal/doctype/website_filter_field/website_filter_field.py index 335d4575b61..8067ebba0fa 100644 --- a/erpnext/portal/doctype/website_filter_field/website_filter_field.py +++ b/erpnext/portal/doctype/website_filter_field/website_filter_field.py @@ -1,8 +1,6 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2019, Frappe Technologies Pvt. Ltd. and contributors # For license information, please see license.txt -from __future__ import unicode_literals from frappe.model.document import Document diff --git a/erpnext/portal/product_configurator/test_product_configurator.py b/erpnext/portal/product_configurator/test_product_configurator.py index 5db74f2c40d..b478489920d 100644 --- a/erpnext/portal/product_configurator/test_product_configurator.py +++ b/erpnext/portal/product_configurator/test_product_configurator.py @@ -1,5 +1,3 @@ -from __future__ import unicode_literals - import unittest import frappe diff --git a/erpnext/portal/utils.py b/erpnext/portal/utils.py index bae8f353b35..974b51ef0a5 100644 --- a/erpnext/portal/utils.py +++ b/erpnext/portal/utils.py @@ -1,5 +1,3 @@ -from __future__ import unicode_literals - import frappe from frappe.utils.nestedset import get_root_of diff --git a/erpnext/projects/doctype/__init__.py b/erpnext/projects/doctype/__init__.py index baffc488252..e69de29bb2d 100644 --- a/erpnext/projects/doctype/__init__.py +++ b/erpnext/projects/doctype/__init__.py @@ -1 +0,0 @@ -from __future__ import unicode_literals diff --git a/erpnext/projects/doctype/activity_cost/activity_cost.py b/erpnext/projects/doctype/activity_cost/activity_cost.py index e210324862b..bc4bb9dcba4 100644 --- a/erpnext/projects/doctype/activity_cost/activity_cost.py +++ b/erpnext/projects/doctype/activity_cost/activity_cost.py @@ -1,8 +1,6 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors and contributors # For license information, please see license.txt -from __future__ import unicode_literals import frappe from frappe import _ diff --git a/erpnext/projects/doctype/activity_cost/test_activity_cost.py b/erpnext/projects/doctype/activity_cost/test_activity_cost.py index c031f3cedab..d53e582adc6 100644 --- a/erpnext/projects/doctype/activity_cost/test_activity_cost.py +++ b/erpnext/projects/doctype/activity_cost/test_activity_cost.py @@ -1,7 +1,5 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors and Contributors # See license.txt -from __future__ import unicode_literals import unittest diff --git a/erpnext/projects/doctype/activity_type/activity_type.py b/erpnext/projects/doctype/activity_type/activity_type.py index 4c94fe45650..5151098bec3 100644 --- a/erpnext/projects/doctype/activity_type/activity_type.py +++ b/erpnext/projects/doctype/activity_type/activity_type.py @@ -1,7 +1,6 @@ # Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors # License: GNU General Public License v3. See license.txt -from __future__ import unicode_literals from frappe.model.document import Document diff --git a/erpnext/projects/doctype/activity_type/test_activity_type.py b/erpnext/projects/doctype/activity_type/test_activity_type.py index 02619af7abd..bb74b881f4c 100644 --- a/erpnext/projects/doctype/activity_type/test_activity_type.py +++ b/erpnext/projects/doctype/activity_type/test_activity_type.py @@ -1,6 +1,5 @@ # Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors # License: GNU General Public License v3. See license.txt -from __future__ import unicode_literals import frappe diff --git a/erpnext/projects/doctype/dependent_task/dependent_task.py b/erpnext/projects/doctype/dependent_task/dependent_task.py index 3f62cef7056..73ce8f9c3d3 100644 --- a/erpnext/projects/doctype/dependent_task/dependent_task.py +++ b/erpnext/projects/doctype/dependent_task/dependent_task.py @@ -1,8 +1,6 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors and contributors # For license information, please see license.txt -from __future__ import unicode_literals from frappe.model.document import Document diff --git a/erpnext/projects/doctype/project/__init__.py b/erpnext/projects/doctype/project/__init__.py index baffc488252..e69de29bb2d 100644 --- a/erpnext/projects/doctype/project/__init__.py +++ b/erpnext/projects/doctype/project/__init__.py @@ -1 +0,0 @@ -from __future__ import unicode_literals diff --git a/erpnext/projects/doctype/project/project.py b/erpnext/projects/doctype/project/project.py index 2a8870b2305..6281c1a8185 100644 --- a/erpnext/projects/doctype/project/project.py +++ b/erpnext/projects/doctype/project/project.py @@ -1,7 +1,6 @@ # Copyright (c) 2017, Frappe Technologies Pvt. Ltd. and Contributors # License: GNU General Public License v3. See license.txt -from __future__ import unicode_literals import frappe from email_reply_parser import EmailReplyParser @@ -144,6 +143,9 @@ class Project(Document): if self.sales_order: frappe.db.set_value("Sales Order", self.sales_order, "project", self.name) + def on_trash(self): + frappe.db.set_value("Sales Order", {"project": self.name}, "project", "") + def update_percent_complete(self): if self.percent_complete_method == "Manual": if self.status == "Completed": diff --git a/erpnext/projects/doctype/project/project_dashboard.py b/erpnext/projects/doctype/project/project_dashboard.py index 64fbbf5ebab..a7d1835848d 100644 --- a/erpnext/projects/doctype/project/project_dashboard.py +++ b/erpnext/projects/doctype/project/project_dashboard.py @@ -1,5 +1,3 @@ -from __future__ import unicode_literals - from frappe import _ diff --git a/erpnext/projects/doctype/project/test_project.py b/erpnext/projects/doctype/project/test_project.py index ebc132626ca..df42e82ad47 100644 --- a/erpnext/projects/doctype/project/test_project.py +++ b/erpnext/projects/doctype/project/test_project.py @@ -1,6 +1,5 @@ # Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors # License: GNU General Public License v3. See license.txt -from __future__ import unicode_literals import unittest @@ -9,6 +8,8 @@ from frappe.utils import add_days, getdate, nowdate from erpnext.projects.doctype.project_template.test_project_template import make_project_template from erpnext.projects.doctype.task.test_task import create_task +from erpnext.selling.doctype.sales_order.sales_order import make_project as make_project_from_so +from erpnext.selling.doctype.sales_order.test_sales_order import make_sales_order test_records = frappe.get_test_records('Project') test_ignore = ["Sales Order"] @@ -96,6 +97,21 @@ class TestProject(unittest.TestCase): self.assertEqual(len(tasks), 2) + def test_project_linking_with_sales_order(self): + so = make_sales_order() + project = make_project_from_so(so.name) + + project.save() + self.assertEqual(project.sales_order, so.name) + + so.reload() + self.assertEqual(so.project, project.name) + + project.delete() + + so.reload() + self.assertFalse(so.project) + def get_project(name, template): project = frappe.get_doc(dict( diff --git a/erpnext/projects/doctype/project_template/project_template.py b/erpnext/projects/doctype/project_template/project_template.py index 493ce5b07cb..3cc8d6855f2 100644 --- a/erpnext/projects/doctype/project_template/project_template.py +++ b/erpnext/projects/doctype/project_template/project_template.py @@ -1,8 +1,6 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2019, Frappe Technologies Pvt. Ltd. and contributors # For license information, please see license.txt -from __future__ import unicode_literals import frappe from frappe import _ diff --git a/erpnext/projects/doctype/project_template/project_template_dashboard.py b/erpnext/projects/doctype/project_template/project_template_dashboard.py index 8eeaa8d6bd8..a03a57dd80d 100644 --- a/erpnext/projects/doctype/project_template/project_template_dashboard.py +++ b/erpnext/projects/doctype/project_template/project_template_dashboard.py @@ -1,6 +1,3 @@ -from __future__ import unicode_literals - - def get_data(): return { 'fieldname': 'project_template', diff --git a/erpnext/projects/doctype/project_template/test_project_template.py b/erpnext/projects/doctype/project_template/test_project_template.py index f71984f3a41..842483343a2 100644 --- a/erpnext/projects/doctype/project_template/test_project_template.py +++ b/erpnext/projects/doctype/project_template/test_project_template.py @@ -1,7 +1,5 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2019, Frappe Technologies Pvt. Ltd. and Contributors # See license.txt -from __future__ import unicode_literals import unittest diff --git a/erpnext/projects/doctype/project_template_task/project_template_task.py b/erpnext/projects/doctype/project_template_task/project_template_task.py index e0861419886..01ec93500c3 100644 --- a/erpnext/projects/doctype/project_template_task/project_template_task.py +++ b/erpnext/projects/doctype/project_template_task/project_template_task.py @@ -1,8 +1,6 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2019, Frappe Technologies Pvt. Ltd. and contributors # For license information, please see license.txt -from __future__ import unicode_literals # import frappe from frappe.model.document import Document diff --git a/erpnext/projects/doctype/project_type/project_type.py b/erpnext/projects/doctype/project_type/project_type.py index 1089483cb3f..4a3724d6a5e 100644 --- a/erpnext/projects/doctype/project_type/project_type.py +++ b/erpnext/projects/doctype/project_type/project_type.py @@ -1,8 +1,6 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2017, Frappe Technologies Pvt. Ltd. and contributors # For license information, please see license.txt -from __future__ import unicode_literals import frappe from frappe import _ diff --git a/erpnext/projects/doctype/project_type/test_project_type.py b/erpnext/projects/doctype/project_type/test_project_type.py index a79020f14ff..3e670d06bd5 100644 --- a/erpnext/projects/doctype/project_type/test_project_type.py +++ b/erpnext/projects/doctype/project_type/test_project_type.py @@ -1,7 +1,5 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2017, Frappe Technologies Pvt. Ltd. and Contributors # See license.txt -from __future__ import unicode_literals import unittest diff --git a/erpnext/projects/doctype/project_update/project_update.py b/erpnext/projects/doctype/project_update/project_update.py index 147e591f8fd..42ba5f6075c 100644 --- a/erpnext/projects/doctype/project_update/project_update.py +++ b/erpnext/projects/doctype/project_update/project_update.py @@ -1,8 +1,6 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2018, Frappe Technologies Pvt. Ltd. and contributors # For license information, please see license.txt -from __future__ import unicode_literals import frappe from frappe.model.document import Document diff --git a/erpnext/projects/doctype/project_update/test_project_update.py b/erpnext/projects/doctype/project_update/test_project_update.py index 15966039799..f29c931ac05 100644 --- a/erpnext/projects/doctype/project_update/test_project_update.py +++ b/erpnext/projects/doctype/project_update/test_project_update.py @@ -1,7 +1,5 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2018, Frappe Technologies Pvt. Ltd. and Contributors # See license.txt -from __future__ import unicode_literals import unittest diff --git a/erpnext/projects/doctype/project_user/project_user.py b/erpnext/projects/doctype/project_user/project_user.py index 7abe9459f24..a52bcb170a0 100644 --- a/erpnext/projects/doctype/project_user/project_user.py +++ b/erpnext/projects/doctype/project_user/project_user.py @@ -1,8 +1,6 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and contributors # For license information, please see license.txt -from __future__ import unicode_literals from frappe.model.document import Document diff --git a/erpnext/projects/doctype/projects_settings/projects_settings.py b/erpnext/projects/doctype/projects_settings/projects_settings.py index 88bb247a3c6..db1dc45d764 100644 --- a/erpnext/projects/doctype/projects_settings/projects_settings.py +++ b/erpnext/projects/doctype/projects_settings/projects_settings.py @@ -1,8 +1,6 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2018, Frappe Technologies Pvt. Ltd. and contributors # For license information, please see license.txt -from __future__ import unicode_literals from frappe.model.document import Document diff --git a/erpnext/projects/doctype/projects_settings/test_projects_settings.py b/erpnext/projects/doctype/projects_settings/test_projects_settings.py index 326624686da..79e78320bb4 100644 --- a/erpnext/projects/doctype/projects_settings/test_projects_settings.py +++ b/erpnext/projects/doctype/projects_settings/test_projects_settings.py @@ -1,7 +1,5 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2018, Frappe Technologies Pvt. Ltd. and Contributors # See license.txt -from __future__ import unicode_literals import unittest diff --git a/erpnext/projects/doctype/task/__init__.py b/erpnext/projects/doctype/task/__init__.py index baffc488252..e69de29bb2d 100644 --- a/erpnext/projects/doctype/task/__init__.py +++ b/erpnext/projects/doctype/task/__init__.py @@ -1 +0,0 @@ -from __future__ import unicode_literals diff --git a/erpnext/projects/doctype/task/task.py b/erpnext/projects/doctype/task/task.py index 6b9062297ed..9b1ea043be6 100755 --- a/erpnext/projects/doctype/task/task.py +++ b/erpnext/projects/doctype/task/task.py @@ -1,7 +1,6 @@ # Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors # License: GNU General Public License v3. See license.txt -from __future__ import unicode_literals import json diff --git a/erpnext/projects/doctype/task/task_dashboard.py b/erpnext/projects/doctype/task/task_dashboard.py index b776b98f676..f7470f8972e 100644 --- a/erpnext/projects/doctype/task/task_dashboard.py +++ b/erpnext/projects/doctype/task/task_dashboard.py @@ -1,5 +1,3 @@ -from __future__ import unicode_literals - from frappe import _ diff --git a/erpnext/projects/doctype/task/test_task.py b/erpnext/projects/doctype/task/test_task.py index 41a9c168dfa..a0ac7c14978 100644 --- a/erpnext/projects/doctype/task/test_task.py +++ b/erpnext/projects/doctype/task/test_task.py @@ -1,6 +1,5 @@ # Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors # License: GNU General Public License v3. See license.txt -from __future__ import unicode_literals import unittest diff --git a/erpnext/projects/doctype/task_depends_on/task_depends_on.py b/erpnext/projects/doctype/task_depends_on/task_depends_on.py index ddb67ee30cb..0db1f81f28d 100644 --- a/erpnext/projects/doctype/task_depends_on/task_depends_on.py +++ b/erpnext/projects/doctype/task_depends_on/task_depends_on.py @@ -1,8 +1,6 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors and contributors # For license information, please see license.txt -from __future__ import unicode_literals from frappe.model.document import Document diff --git a/erpnext/projects/doctype/task_type/task_type.py b/erpnext/projects/doctype/task_type/task_type.py index 5aacf8a2395..08bed6973d0 100644 --- a/erpnext/projects/doctype/task_type/task_type.py +++ b/erpnext/projects/doctype/task_type/task_type.py @@ -1,8 +1,6 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2019, Frappe Technologies Pvt. Ltd. and contributors # For license information, please see license.txt -from __future__ import unicode_literals # import frappe from frappe.model.document import Document diff --git a/erpnext/projects/doctype/task_type/test_task_type.py b/erpnext/projects/doctype/task_type/test_task_type.py index 7690c3775af..ef99402f7ad 100644 --- a/erpnext/projects/doctype/task_type/test_task_type.py +++ b/erpnext/projects/doctype/task_type/test_task_type.py @@ -1,7 +1,5 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2019, Frappe Technologies Pvt. Ltd. and Contributors # See license.txt -from __future__ import unicode_literals import unittest diff --git a/erpnext/projects/doctype/timesheet/test_timesheet.py b/erpnext/projects/doctype/timesheet/test_timesheet.py index 6b32c66dfe5..d59cc01013b 100644 --- a/erpnext/projects/doctype/timesheet/test_timesheet.py +++ b/erpnext/projects/doctype/timesheet/test_timesheet.py @@ -1,7 +1,5 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors # See license.txt -from __future__ import unicode_literals import datetime import unittest diff --git a/erpnext/projects/doctype/timesheet/timesheet.js b/erpnext/projects/doctype/timesheet/timesheet.js index 1655b76b988..f615f051f0c 100644 --- a/erpnext/projects/doctype/timesheet/timesheet.js +++ b/erpnext/projects/doctype/timesheet/timesheet.js @@ -32,12 +32,12 @@ frappe.ui.form.on("Timesheet", { }; }, - onload: function(frm){ + onload: function(frm) { if (frm.doc.__islocal && frm.doc.time_logs) { calculate_time_and_amount(frm); } - if (frm.is_new()) { + if (frm.is_new() && !frm.doc.employee) { set_employee_and_company(frm); } }, @@ -283,7 +283,9 @@ frappe.ui.form.on("Timesheet Detail", { calculate_time_and_amount(frm); }, - activity_type: function(frm, cdt, cdn) { + activity_type: function (frm, cdt, cdn) { + if (!frappe.get_doc(cdt, cdn).activity_type) return; + frappe.call({ method: "erpnext.projects.doctype.timesheet.timesheet.get_activity_cost", args: { @@ -291,10 +293,10 @@ frappe.ui.form.on("Timesheet Detail", { activity_type: frm.selected_doc.activity_type, currency: frm.doc.currency }, - callback: function(r){ - if(r.message){ - frappe.model.set_value(cdt, cdn, 'billing_rate', r.message['billing_rate']); - frappe.model.set_value(cdt, cdn, 'costing_rate', r.message['costing_rate']); + callback: function (r) { + if (r.message) { + frappe.model.set_value(cdt, cdn, "billing_rate", r.message["billing_rate"]); + frappe.model.set_value(cdt, cdn, "costing_rate", r.message["costing_rate"]); calculate_billing_costing_amount(frm, cdt, cdn); } } diff --git a/erpnext/projects/doctype/timesheet/timesheet.py b/erpnext/projects/doctype/timesheet/timesheet.py index e144e82a7d5..e92785e06cf 100644 --- a/erpnext/projects/doctype/timesheet/timesheet.py +++ b/erpnext/projects/doctype/timesheet/timesheet.py @@ -1,8 +1,6 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and contributors # For license information, please see license.txt -from __future__ import unicode_literals import json @@ -215,25 +213,47 @@ class Timesheet(Document): @frappe.whitelist() def get_projectwise_timesheet_data(project=None, parent=None, from_time=None, to_time=None): - condition = '' + condition = "" if project: - condition += "and tsd.project = %(project)s" + condition += "AND tsd.project = %(project)s " if parent: - condition += "AND tsd.parent = %(parent)s" + condition += "AND tsd.parent = %(parent)s " if from_time and to_time: condition += "AND CAST(tsd.from_time as DATE) BETWEEN %(from_time)s AND %(to_time)s" - return frappe.db.sql("""SELECT tsd.name as name, - tsd.parent as parent, tsd.billing_hours as billing_hours, - tsd.billing_amount as billing_amount, tsd.activity_type as activity_type, - tsd.description as description, ts.currency as currency, - tsd.project_name as project_name - FROM `tabTimesheet Detail` tsd - INNER JOIN `tabTimesheet` ts ON ts.name = tsd.parent - WHERE tsd.parenttype = 'Timesheet' - and tsd.docstatus=1 {0} - and tsd.is_billable = 1 - and tsd.sales_invoice is null""".format(condition), {'project': project, 'parent': parent, 'from_time': from_time, 'to_time': to_time}, as_dict=1) + query = f""" + SELECT + tsd.name as name, + tsd.parent as time_sheet, + tsd.from_time as from_time, + tsd.to_time as to_time, + tsd.billing_hours as billing_hours, + tsd.billing_amount as billing_amount, + tsd.activity_type as activity_type, + tsd.description as description, + ts.currency as currency, + tsd.project_name as project_name + FROM `tabTimesheet Detail` tsd + INNER JOIN `tabTimesheet` ts + ON ts.name = tsd.parent + WHERE + tsd.parenttype = 'Timesheet' + AND tsd.docstatus = 1 + AND tsd.is_billable = 1 + AND tsd.sales_invoice is NULL + {condition} + ORDER BY tsd.from_time ASC + """ + + filters = { + "project": project, + "parent": parent, + "from_time": from_time, + "to_time": to_time + } + + return frappe.db.sql(query, filters, as_dict=1) + @frappe.whitelist() def get_timesheet_detail_rate(timelog, currency): diff --git a/erpnext/projects/doctype/timesheet/timesheet_dashboard.py b/erpnext/projects/doctype/timesheet/timesheet_dashboard.py index 3ef1d92dcdb..15fe797e23a 100644 --- a/erpnext/projects/doctype/timesheet/timesheet_dashboard.py +++ b/erpnext/projects/doctype/timesheet/timesheet_dashboard.py @@ -1,5 +1,3 @@ -from __future__ import unicode_literals - from frappe import _ diff --git a/erpnext/projects/doctype/timesheet_detail/timesheet_detail.py b/erpnext/projects/doctype/timesheet_detail/timesheet_detail.py index 4fd233ebb21..d527a3c9223 100644 --- a/erpnext/projects/doctype/timesheet_detail/timesheet_detail.py +++ b/erpnext/projects/doctype/timesheet_detail/timesheet_detail.py @@ -1,8 +1,6 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and contributors # For license information, please see license.txt -from __future__ import unicode_literals from frappe.model.document import Document diff --git a/erpnext/projects/report/billing_summary.py b/erpnext/projects/report/billing_summary.py index dec2824fcc0..46479d0a19b 100644 --- a/erpnext/projects/report/billing_summary.py +++ b/erpnext/projects/report/billing_summary.py @@ -2,7 +2,6 @@ # For license information, please see license.txt -from __future__ import unicode_literals import frappe from frappe import _ diff --git a/erpnext/projects/report/daily_timesheet_summary/daily_timesheet_summary.py b/erpnext/projects/report/daily_timesheet_summary/daily_timesheet_summary.py index 3a33b4b1a7e..f73376871aa 100644 --- a/erpnext/projects/report/daily_timesheet_summary/daily_timesheet_summary.py +++ b/erpnext/projects/report/daily_timesheet_summary/daily_timesheet_summary.py @@ -1,7 +1,6 @@ # Copyright (c) 2013, Frappe Technologies Pvt. Ltd. and contributors # For license information, please see license.txt -from __future__ import unicode_literals import frappe from frappe import _ diff --git a/erpnext/projects/report/delayed_tasks_summary/delayed_tasks_summary.py b/erpnext/projects/report/delayed_tasks_summary/delayed_tasks_summary.py index 301639015c3..3ab2bb652b0 100644 --- a/erpnext/projects/report/delayed_tasks_summary/delayed_tasks_summary.py +++ b/erpnext/projects/report/delayed_tasks_summary/delayed_tasks_summary.py @@ -1,7 +1,6 @@ # Copyright (c) 2013, Frappe Technologies Pvt. Ltd. and contributors # For license information, please see license.txt -from __future__ import unicode_literals import frappe from frappe.utils import date_diff, nowdate diff --git a/erpnext/projects/report/delayed_tasks_summary/test_delayed_tasks_summary.py b/erpnext/projects/report/delayed_tasks_summary/test_delayed_tasks_summary.py index 88c77c88b43..e2ba7c2c268 100644 --- a/erpnext/projects/report/delayed_tasks_summary/test_delayed_tasks_summary.py +++ b/erpnext/projects/report/delayed_tasks_summary/test_delayed_tasks_summary.py @@ -1,5 +1,3 @@ -from __future__ import unicode_literals - import unittest import frappe diff --git a/erpnext/projects/report/employee_billing_summary/employee_billing_summary.py b/erpnext/projects/report/employee_billing_summary/employee_billing_summary.py index 30bd9f0182f..a2f7378d1b7 100644 --- a/erpnext/projects/report/employee_billing_summary/employee_billing_summary.py +++ b/erpnext/projects/report/employee_billing_summary/employee_billing_summary.py @@ -1,7 +1,6 @@ # Copyright (c) 2013, Frappe Technologies Pvt. Ltd. and contributors # For license information, please see license.txt -from __future__ import unicode_literals import frappe diff --git a/erpnext/projects/report/employee_hours_utilization_based_on_timesheet/employee_hours_utilization_based_on_timesheet.py b/erpnext/projects/report/employee_hours_utilization_based_on_timesheet/employee_hours_utilization_based_on_timesheet.py index d59a2ac52a6..dd4f8ea7865 100644 --- a/erpnext/projects/report/employee_hours_utilization_based_on_timesheet/employee_hours_utilization_based_on_timesheet.py +++ b/erpnext/projects/report/employee_hours_utilization_based_on_timesheet/employee_hours_utilization_based_on_timesheet.py @@ -1,12 +1,10 @@ # Copyright (c) 2013, Frappe Technologies Pvt. Ltd. and contributors # For license information, please see license.txt -from __future__ import unicode_literals import frappe from frappe import _ from frappe.utils import flt, getdate -from six import iteritems def execute(filters=None): @@ -111,7 +109,7 @@ class EmployeeHoursReport: self.data = [] - for emp, data in iteritems(self.stats_by_employee): + for emp, data in self.stats_by_employee.items(): row = frappe._dict() row['employee'] = emp row.update(data) @@ -181,7 +179,7 @@ class EmployeeHoursReport: def calculate_utilizations(self): TOTAL_HOURS = flt(self.standard_working_hours * self.day_span, 2) - for emp, data in iteritems(self.stats_by_employee): + for emp, data in self.stats_by_employee.items(): data['total_hours'] = TOTAL_HOURS data['untracked_hours'] = flt(TOTAL_HOURS - data['billed_hours'] - data['non_billed_hours'], 2) diff --git a/erpnext/projects/report/employee_hours_utilization_based_on_timesheet/test_employee_util.py b/erpnext/projects/report/employee_hours_utilization_based_on_timesheet/test_employee_util.py index f456c84a588..b500bc8ab7e 100644 --- a/erpnext/projects/report/employee_hours_utilization_based_on_timesheet/test_employee_util.py +++ b/erpnext/projects/report/employee_hours_utilization_based_on_timesheet/test_employee_util.py @@ -1,5 +1,3 @@ -from __future__ import unicode_literals - import unittest import frappe diff --git a/erpnext/projects/report/project_billing_summary/project_billing_summary.py b/erpnext/projects/report/project_billing_summary/project_billing_summary.py index 30bd9f0182f..a2f7378d1b7 100644 --- a/erpnext/projects/report/project_billing_summary/project_billing_summary.py +++ b/erpnext/projects/report/project_billing_summary/project_billing_summary.py @@ -1,7 +1,6 @@ # Copyright (c) 2013, Frappe Technologies Pvt. Ltd. and contributors # For license information, please see license.txt -from __future__ import unicode_literals import frappe diff --git a/erpnext/projects/report/project_profitability/project_profitability.py b/erpnext/projects/report/project_profitability/project_profitability.py index 13e02c89355..9520cd17be2 100644 --- a/erpnext/projects/report/project_profitability/project_profitability.py +++ b/erpnext/projects/report/project_profitability/project_profitability.py @@ -1,7 +1,6 @@ # Copyright (c) 2013, Frappe Technologies Pvt. Ltd. and contributors # For license information, please see license.txt -from __future__ import unicode_literals import frappe from frappe import _ diff --git a/erpnext/projects/report/project_profitability/test_project_profitability.py b/erpnext/projects/report/project_profitability/test_project_profitability.py index 8cf169b38f4..2cf9d38bd02 100644 --- a/erpnext/projects/report/project_profitability/test_project_profitability.py +++ b/erpnext/projects/report/project_profitability/test_project_profitability.py @@ -1,5 +1,3 @@ -from __future__ import unicode_literals - import unittest import frappe diff --git a/erpnext/projects/report/project_summary/project_summary.py b/erpnext/projects/report/project_summary/project_summary.py index dbb4e848578..ce1b70160c8 100644 --- a/erpnext/projects/report/project_summary/project_summary.py +++ b/erpnext/projects/report/project_summary/project_summary.py @@ -1,7 +1,6 @@ # Copyright (c) 2013, Frappe Technologies Pvt. Ltd. and contributors # For license information, please see license.txt -from __future__ import unicode_literals import frappe from frappe import _ diff --git a/erpnext/projects/report/project_wise_stock_tracking/project_wise_stock_tracking.py b/erpnext/projects/report/project_wise_stock_tracking/project_wise_stock_tracking.py index 5d2b7dbc5be..31bcc3b2ca3 100644 --- a/erpnext/projects/report/project_wise_stock_tracking/project_wise_stock_tracking.py +++ b/erpnext/projects/report/project_wise_stock_tracking/project_wise_stock_tracking.py @@ -1,6 +1,5 @@ # Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors # License: GNU General Public License v3. See license.txt -from __future__ import unicode_literals import frappe from frappe import _ diff --git a/erpnext/projects/utils.py b/erpnext/projects/utils.py index 69264704b4b..5d7455039af 100644 --- a/erpnext/projects/utils.py +++ b/erpnext/projects/utils.py @@ -3,7 +3,6 @@ # For license information, please see license.txt -from __future__ import unicode_literals import frappe diff --git a/erpnext/projects/web_form/tasks/tasks.py b/erpnext/projects/web_form/tasks/tasks.py index aed794261ea..99249edff14 100644 --- a/erpnext/projects/web_form/tasks/tasks.py +++ b/erpnext/projects/web_form/tasks/tasks.py @@ -1,5 +1,3 @@ -from __future__ import unicode_literals - import frappe diff --git a/erpnext/projects/workspace/projects/projects.json b/erpnext/projects/workspace/projects/projects.json index 065f1eda1f3..1df2b089839 100644 --- a/erpnext/projects/workspace/projects/projects.json +++ b/erpnext/projects/workspace/projects/projects.json @@ -1,5 +1,4 @@ { - "category": "", "charts": [ { "chart_name": "Project Summary", @@ -8,18 +7,12 @@ ], "content": "[{\"type\": \"chart\", \"data\": {\"chart_name\": \"Open Projects\", \"col\": 12}}, {\"type\": \"spacer\", \"data\": {\"col\": 12}}, {\"type\": \"header\", \"data\": {\"text\": \"Your Shortcuts\", \"level\": 4, \"col\": 12}}, {\"type\": \"shortcut\", \"data\": {\"shortcut_name\": \"Task\", \"col\": 4}}, {\"type\": \"shortcut\", \"data\": {\"shortcut_name\": \"Project\", \"col\": 4}}, {\"type\": \"shortcut\", \"data\": {\"shortcut_name\": \"Timesheet\", \"col\": 4}}, {\"type\": \"shortcut\", \"data\": {\"shortcut_name\": \"Project Billing Summary\", \"col\": 4}}, {\"type\": \"shortcut\", \"data\": {\"shortcut_name\": \"Dashboard\", \"col\": 4}}, {\"type\": \"spacer\", \"data\": {\"col\": 12}}, {\"type\": \"header\", \"data\": {\"text\": \"Reports & Masters\", \"level\": 4, \"col\": 12}}, {\"type\": \"card\", \"data\": {\"card_name\": \"Projects\", \"col\": 4}}, {\"type\": \"card\", \"data\": {\"card_name\": \"Time Tracking\", \"col\": 4}}, {\"type\": \"card\", \"data\": {\"card_name\": \"Reports\", \"col\": 4}}]", "creation": "2020-03-02 15:46:04.874669", - "developer_mode_only": 0, - "disable_user_customization": 0, "docstatus": 0, "doctype": "Workspace", - "extends": "", - "extends_another_page": 0, "for_user": "", "hide_custom": 0, "icon": "project", "idx": 0, - "is_default": 0, - "is_standard": 0, "label": "Projects", "links": [ { @@ -201,15 +194,12 @@ "type": "Link" } ], - "modified": "2021-08-05 12:16:01.540145", + "modified": "2021-08-05 12:16:01.540147", "modified_by": "Administrator", "module": "Projects", "name": "Projects", - "onboarding": "", "owner": "Administrator", "parent_page": "", - "pin_to_bottom": 0, - "pin_to_top": 0, "public": 1, "restrict_to_domain": "", "roles": [], diff --git a/erpnext/public/build.json b/erpnext/public/build.json index 6b70dab8037..f8e817770d5 100644 --- a/erpnext/public/build.json +++ b/erpnext/public/build.json @@ -1,14 +1,10 @@ { "css/erpnext.css": [ "public/less/erpnext.less", - "public/less/hub.less", "public/scss/call_popup.scss", "public/scss/point-of-sale.scss", "public/scss/hierarchy_chart.scss" ], - "css/marketplace.css": [ - "public/less/hub.less" - ], "js/erpnext-web.min.js": [ "public/js/website_utils.js", "public/js/shopping_cart.js" @@ -17,9 +13,6 @@ "public/scss/website.scss", "public/scss/shopping_cart.scss" ], - "js/marketplace.min.js": [ - "public/js/hub/marketplace.js" - ], "js/erpnext.min.js": [ "public/js/conf.js", "public/js/utils.js", @@ -41,7 +34,6 @@ "public/js/utils/supplier_quick_entry.js", "public/js/education/student_button.html", "public/js/education/assessment_result_tool.html", - "public/js/hub/hub_factory.js", "public/js/call_popup/call_popup.js", "public/js/utils/dimension_tree_filter.js", "public/js/telephony.js", diff --git a/erpnext/public/images/hub_logo.svg b/erpnext/public/images/hub_logo.svg deleted file mode 100644 index 4af482176ea..00000000000 --- a/erpnext/public/images/hub_logo.svg +++ /dev/null @@ -1,112 +0,0 @@ - - - - - - - - - - image/svg+xml - - - - - - - - - - - - - - - - - - - - - - diff --git a/erpnext/public/js/bank_reconciliation_tool/dialog_manager.js b/erpnext/public/js/bank_reconciliation_tool/dialog_manager.js index 239fbb92b11..ca73393c546 100644 --- a/erpnext/public/js/bank_reconciliation_tool/dialog_manager.js +++ b/erpnext/public/js/bank_reconciliation_tool/dialog_manager.js @@ -227,7 +227,7 @@ erpnext.accounts.bank_reconciliation.DialogManager = class DialogManager { { fieldtype: "HTML", fieldname: "no_matching_vouchers", - options: "
No Matching Vouchers Found
" + options: "
No Matching Vouchers Found
" }, { fieldtype: "Section Break", diff --git a/erpnext/public/js/controllers/buying.js b/erpnext/public/js/controllers/buying.js index 86dadd36d6e..d696ef55ae6 100644 --- a/erpnext/public/js/controllers/buying.js +++ b/erpnext/public/js/controllers/buying.js @@ -165,45 +165,33 @@ erpnext.buying.BuyingController = class BuyingController extends erpnext.Transac } qty(doc, cdt, cdn) { - var item = frappe.get_doc(cdt, cdn); if ((doc.doctype == "Purchase Receipt") || (doc.doctype == "Purchase Invoice" && (doc.update_stock || doc.is_return))) { - frappe.model.round_floats_in(item, ["qty", "received_qty"]); - - if(!doc.is_return && this.validate_negative_quantity(cdt, cdn, item, ["qty", "received_qty"])){ return } - - if(!item.rejected_qty && item.qty) { - item.received_qty = item.qty; - } - - frappe.model.round_floats_in(item, ["qty", "received_qty"]); - item.rejected_qty = flt(item.received_qty - item.qty, precision("rejected_qty", item)); - item.received_stock_qty = flt(item.conversion_factor, precision("conversion_factor", item)) * flt(item.received_qty); + this.calculate_received_qty(doc, cdt, cdn) } super.qty(doc, cdt, cdn); } + rejected_qty(doc, cdt, cdn) { + this.calculate_received_qty(doc, cdt, cdn) + } + + calculate_received_qty(doc, cdt, cdn){ + var item = frappe.get_doc(cdt, cdn); + frappe.model.round_floats_in(item, ["qty", "rejected_qty"]); + + if(!doc.is_return && this.validate_negative_quantity(cdt, cdn, item, ["qty", "rejected_qty"])){ return } + + let received_qty = flt(item.qty + item.rejected_qty, precision("received_qty", item)); + let received_stock_qty = flt(item.conversion_factor, precision("conversion_factor", item)) * flt(received_qty); + + frappe.model.set_value(cdt, cdn, "received_qty", received_qty); + frappe.model.set_value(cdt, cdn, "received_stock_qty", received_stock_qty); + } + batch_no(doc, cdt, cdn) { super.batch_no(doc, cdt, cdn); } - received_qty(doc, cdt, cdn) { - this.calculate_accepted_qty(doc, cdt, cdn) - } - - rejected_qty(doc, cdt, cdn) { - this.calculate_accepted_qty(doc, cdt, cdn) - } - - calculate_accepted_qty(doc, cdt, cdn){ - var item = frappe.get_doc(cdt, cdn); - frappe.model.round_floats_in(item, ["received_qty", "rejected_qty"]); - - if(!doc.is_return && this.validate_negative_quantity(cdt, cdn, item, ["received_qty", "rejected_qty"])){ return } - - item.qty = flt(item.received_qty - item.rejected_qty, precision("qty", item)); - this.qty(doc, cdt, cdn); - } - validate_negative_quantity(cdt, cdn, item, fieldnames){ if(!item || !fieldnames) { return } diff --git a/erpnext/public/js/controllers/taxes_and_totals.js b/erpnext/public/js/controllers/taxes_and_totals.js index 702064fe556..7c1c8c7e46e 100644 --- a/erpnext/public/js/controllers/taxes_and_totals.js +++ b/erpnext/public/js/controllers/taxes_and_totals.js @@ -81,6 +81,7 @@ erpnext.taxes_and_totals = class TaxesAndTotals extends erpnext.payments { this.initialize_taxes(); this.determine_exclusive_rate(); this.calculate_net_total(); + this.calculate_shipping_charges(); this.calculate_taxes(); this.manipulate_grand_total_for_inclusive_tax(); this.calculate_totals(); @@ -137,7 +138,9 @@ erpnext.taxes_and_totals = class TaxesAndTotals extends erpnext.payments { var me = this; $.each(this.frm.doc["taxes"] || [], function(i, tax) { - tax.item_wise_tax_detail = {}; + if (!tax.dont_recompute_tax) { + tax.item_wise_tax_detail = {}; + } var tax_fields = ["total", "tax_amount_after_discount_amount", "tax_amount_for_current_item", "grand_total_for_current_item", "tax_fraction_for_current_item", "grand_total_fraction_for_current_item"]; @@ -264,8 +267,13 @@ erpnext.taxes_and_totals = class TaxesAndTotals extends erpnext.payments { me.frm.doc.net_total += item.net_amount; me.frm.doc.base_net_total += item.base_net_amount; }); + } + calculate_shipping_charges() { frappe.model.round_floats_in(this.frm.doc, ["total", "base_total", "net_total", "base_net_total"]); + if (frappe.meta.get_docfield(this.frm.doc.doctype, "shipping_rule", this.frm.doc.name)) { + this.shipping_rule(); + } } add_taxes_from_item_tax_template(item_tax_map) { @@ -421,7 +429,9 @@ erpnext.taxes_and_totals = class TaxesAndTotals extends erpnext.payments { current_tax_amount = tax_rate * item.qty; } - this.set_item_wise_tax(item, tax, tax_rate, current_tax_amount); + if (!tax.dont_recompute_tax) { + this.set_item_wise_tax(item, tax, tax_rate, current_tax_amount); + } return current_tax_amount; } @@ -589,7 +599,9 @@ erpnext.taxes_and_totals = class TaxesAndTotals extends erpnext.payments { delete tax[fieldname]; }); - tax.item_wise_tax_detail = JSON.stringify(tax.item_wise_tax_detail); + if (!tax.dont_recompute_tax) { + tax.item_wise_tax_detail = JSON.stringify(tax.item_wise_tax_detail); + } }); } } diff --git a/erpnext/public/js/controllers/transaction.js b/erpnext/public/js/controllers/transaction.js index 5f8966f88ab..0cfc008c13a 100644 --- a/erpnext/public/js/controllers/transaction.js +++ b/erpnext/public/js/controllers/transaction.js @@ -345,26 +345,14 @@ erpnext.TransactionController = class TransactionController extends erpnext.taxe } scan_barcode() { - let scan_barcode_field = this.frm.fields_dict["scan_barcode"]; - - let show_description = function(idx, exist = null) { - if (exist) { - frappe.show_alert({ - message: __('Row #{0}: Qty increased by 1', [idx]), - indicator: 'green' - }); - } else { - frappe.show_alert({ - message: __('Row #{0}: Item added', [idx]), - indicator: 'green' - }); - } - } + let me = this; if(this.frm.doc.scan_barcode) { frappe.call({ method: "erpnext.selling.page.point_of_sale.point_of_sale.search_for_serial_or_batch_or_barcode_number", - args: { search_value: this.frm.doc.scan_barcode } + args: { + search_value: this.frm.doc.scan_barcode + } }).then(r => { const data = r && r.message; if (!data || Object.keys(data).length === 0) { @@ -375,49 +363,96 @@ erpnext.TransactionController = class TransactionController extends erpnext.taxe return; } - let cur_grid = this.frm.fields_dict.items.grid; - - let row_to_modify = null; - const existing_item_row = this.frm.doc.items.find(d => d.item_code === data.item_code); - const blank_item_row = this.frm.doc.items.find(d => !d.item_code); - - if (existing_item_row) { - row_to_modify = existing_item_row; - } else if (blank_item_row) { - row_to_modify = blank_item_row; - } - - if (!row_to_modify) { - // add new row - row_to_modify = frappe.model.add_child(this.frm.doc, cur_grid.doctype, 'items'); - } - - show_description(row_to_modify.idx, row_to_modify.item_code); - - this.frm.from_barcode = this.frm.from_barcode ? this.frm.from_barcode + 1 : 1; - frappe.model.set_value(row_to_modify.doctype, row_to_modify.name, { - item_code: data.item_code, - qty: (row_to_modify.qty || 0) + 1 - }); - - ['serial_no', 'batch_no', 'barcode'].forEach(field => { - if (data[field] && frappe.meta.has_field(row_to_modify.doctype, field)) { - - let value = (row_to_modify[field] && field === "serial_no") - ? row_to_modify[field] + '\n' + data[field] : data[field]; - - frappe.model.set_value(row_to_modify.doctype, - row_to_modify.name, field, value); - } - }); - - scan_barcode_field.set_value(''); - refresh_field("items"); + me.modify_table_after_scan(data); }); } return false; } + modify_table_after_scan(data) { + let scan_barcode_field = this.frm.fields_dict["scan_barcode"]; + let cur_grid = this.frm.fields_dict.items.grid; + let row_to_modify = null; + + // Check if batch is scanned and table has batch no field + let batch_no_scan = Boolean(data.batch_no) && frappe.meta.has_field(cur_grid.doctype, "batch_no"); + + if (batch_no_scan) { + row_to_modify = this.get_batch_row_to_modify(data.batch_no); + } else { + // serial or barcode scan + row_to_modify = this.get_row_to_modify_on_scan(row_to_modify, data); + } + + if (!row_to_modify) { + // add new row if new item/batch is scanned + row_to_modify = frappe.model.add_child(this.frm.doc, cur_grid.doctype, 'items'); + } + + this.show_scan_message(row_to_modify.idx, row_to_modify.item_code); + this.set_scanned_values(row_to_modify, data, scan_barcode_field); + } + + set_scanned_values(row_to_modify, data, scan_barcode_field) { + // increase qty and set scanned value and item in row + this.frm.from_barcode = this.frm.from_barcode ? this.frm.from_barcode + 1 : 1; + frappe.model.set_value(row_to_modify.doctype, row_to_modify.name, { + item_code: data.item_code, + qty: (row_to_modify.qty || 0) + 1 + }); + + ['serial_no', 'batch_no', 'barcode'].forEach(field => { + if (data[field] && frappe.meta.has_field(row_to_modify.doctype, field)) { + let is_serial_no = row_to_modify[field] && field === "serial_no"; + let value = data[field]; + + if (is_serial_no) { + value = row_to_modify[field] + '\n' + data[field]; + } + + frappe.model.set_value(row_to_modify.doctype, row_to_modify.name, field, value); + } + }); + + scan_barcode_field.set_value(''); + refresh_field("items"); + } + + get_row_to_modify_on_scan(row_to_modify, data) { + // get an existing item row to increment or blank row to modify + const existing_item_row = this.frm.doc.items.find(d => d.item_code === data.item_code); + const blank_item_row = this.frm.doc.items.find(d => !d.item_code); + + if (existing_item_row) { + row_to_modify = existing_item_row; + } else if (blank_item_row) { + row_to_modify = blank_item_row; + } + + return row_to_modify; + } + + get_batch_row_to_modify(batch_no) { + // get row if batch already exists in table + const existing_batch_row = this.frm.doc.items.find(d => d.batch_no === batch_no); + return existing_batch_row || null; + } + + show_scan_message (idx, exist = null) { + // show new row or qty increase toast + if (exist) { + frappe.show_alert({ + message: __('Row #{0}: Qty increased by 1', [idx]), + indicator: 'green' + }); + } else { + frappe.show_alert({ + message: __('Row #{0}: Item added', [idx]), + indicator: 'green' + }); + } + } + apply_default_taxes() { var me = this; var taxes_and_charges_field = frappe.meta.get_docfield(me.frm.doc.doctype, "taxes_and_charges", @@ -487,6 +522,10 @@ erpnext.TransactionController = class TransactionController extends erpnext.taxe var me = this; var item = frappe.get_doc(cdt, cdn); var update_stock = 0, show_batch_dialog = 0; + + item.weight_per_unit = 0; + item.weight_uom = ''; + if(['Sales Invoice'].includes(this.frm.doc.doctype)) { update_stock = cint(me.frm.doc.update_stock); show_batch_dialog = update_stock; @@ -613,6 +652,7 @@ erpnext.TransactionController = class TransactionController extends erpnext.taxe me.frm.script_manager.trigger('qty', item.doctype, item.name); if (!me.frm.doc.set_warehouse) me.frm.script_manager.trigger('warehouse', item.doctype, item.name); + me.apply_price_list(item, true); }, undefined, !frappe.flags.hide_serial_batch_dialog); } }, @@ -880,7 +920,9 @@ erpnext.TransactionController = class TransactionController extends erpnext.taxe if (r.message) { me.frm.set_value("billing_address", r.message); } else { - me.frm.set_value("company_address", ""); + if (frappe.meta.get_docfield(me.frm.doctype, 'company_address')) { + me.frm.set_value("company_address", ""); + } } } }); @@ -1043,16 +1085,8 @@ erpnext.TransactionController = class TransactionController extends erpnext.taxe return this.frm.call({ doc: this.frm.doc, method: "apply_shipping_rule", - callback: function(r) { - if(!r.exc) { - me.calculate_taxes_and_totals(); - } - } }).fail(() => this.frm.set_value('shipping_rule', '')); } - else { - me.calculate_taxes_and_totals(); - } } set_margin_amount_based_on_currency(exchange_rate) { diff --git a/erpnext/public/js/erpnext.bundle.js b/erpnext/public/js/erpnext.bundle.js index febdb24da34..5259bdcc765 100644 --- a/erpnext/public/js/erpnext.bundle.js +++ b/erpnext/public/js/erpnext.bundle.js @@ -18,7 +18,6 @@ import "./utils/customer_quick_entry"; import "./utils/supplier_quick_entry"; import "./education/student_button.html"; import "./education/assessment_result_tool.html"; -import "./hub/hub_factory"; import "./call_popup/call_popup"; import "./utils/dimension_tree_filter"; import "./telephony"; diff --git a/erpnext/public/js/financial_statements.js b/erpnext/public/js/financial_statements.js index 0d79b10c041..1a309ba0156 100644 --- a/erpnext/public/js/financial_statements.js +++ b/erpnext/public/js/financial_statements.js @@ -113,15 +113,15 @@ function get_filters() { "fieldname":"period_start_date", "label": __("Start Date"), "fieldtype": "Date", - "hidden": 1, - "reqd": 1 + "reqd": 1, + "depends_on": "eval:doc.filter_based_on == 'Date Range'" }, { "fieldname":"period_end_date", "label": __("End Date"), "fieldtype": "Date", - "hidden": 1, - "reqd": 1 + "reqd": 1, + "depends_on": "eval:doc.filter_based_on == 'Date Range'" }, { "fieldname":"from_fiscal_year", @@ -129,7 +129,8 @@ function get_filters() { "fieldtype": "Link", "options": "Fiscal Year", "default": frappe.defaults.get_user_default("fiscal_year"), - "reqd": 1 + "reqd": 1, + "depends_on": "eval:doc.filter_based_on == 'Fiscal Year'" }, { "fieldname":"to_fiscal_year", @@ -137,7 +138,8 @@ function get_filters() { "fieldtype": "Link", "options": "Fiscal Year", "default": frappe.defaults.get_user_default("fiscal_year"), - "reqd": 1 + "reqd": 1, + "depends_on": "eval:doc.filter_based_on == 'Fiscal Year'" }, { "fieldname": "periodicity", diff --git a/erpnext/public/js/help_links.js b/erpnext/public/js/help_links.js index d0c935f4887..b643ccae947 100644 --- a/erpnext/public/js/help_links.js +++ b/erpnext/public/js/help_links.js @@ -5,7 +5,7 @@ const docsUrl = "https://erpnext.com/docs/"; frappe.help.help_links["Form/Rename Tool"] = [ { label: "Bulk Rename", - url: docsUrl + "user/manual/en/setting-up/data/bulk-rename", + url: docsUrl + "user/manual/en/using-erpnext/articles/bulk-rename", }, ]; @@ -59,10 +59,23 @@ frappe.help.help_links["Form/System Settings"] = [ }, ]; -frappe.help.help_links["data-import-tool"] = [ +frappe.help.help_links["Form/Data Import"] = [ { label: "Importing and Exporting Data", - url: docsUrl + "user/manual/en/setting-up/data/data-import-tool", + url: docsUrl + "user/manual/en/setting-up/data/data-import", + }, + { + label: "Overwriting Data from Data Import Tool", + url: + docsUrl + + "user/manual/en/setting-up/articles/overwriting-data-from-data-import-tool", + }, +]; + +frappe.help.help_links["List/Data Import"] = [ + { + label: "Importing and Exporting Data", + url: docsUrl + "user/manual/en/setting-up/data/data-import", }, { label: "Overwriting Data from Data Import Tool", @@ -101,14 +114,14 @@ frappe.help.help_links["Form/Global Defaults"] = [ }, ]; -frappe.help.help_links["Form/Email Digest"] = [ +frappe.help.help_links["List/Print Heading"] = [ { - label: "Email Digest", - url: docsUrl + "user/manual/en/setting-up/email/email-digest", + label: "Print Heading", + url: docsUrl + "user/manual/en/setting-up/print/print-headings", }, ]; -frappe.help.help_links["List/Print Heading"] = [ +frappe.help.help_links["Form/Print Heading"] = [ { label: "Print Heading", url: docsUrl + "user/manual/en/setting-up/print/print-headings", @@ -153,18 +166,25 @@ frappe.help.help_links["List/Email Account"] = [ frappe.help.help_links["List/Notification"] = [ { label: "Notification", - url: docsUrl + "user/manual/en/setting-up/email/notifications", + url: docsUrl + "user/manual/en/setting-up/notifications", }, ]; frappe.help.help_links["Form/Notification"] = [ { label: "Notification", - url: docsUrl + "user/manual/en/setting-up/email/notifications", + url: docsUrl + "user/manual/en/setting-up/notifications", }, ]; -frappe.help.help_links["List/Email Digest"] = [ +frappe.help.help_links["Form/Email Digest"] = [ + { + label: "Email Digest", + url: docsUrl + "user/manual/en/setting-up/email/email-digest", + }, +]; + +frappe.help.help_links["Form/Email Digest"] = [ { label: "Email Digest", url: docsUrl + "user/manual/en/setting-up/email/email-digest", @@ -174,7 +194,7 @@ frappe.help.help_links["List/Email Digest"] = [ frappe.help.help_links["List/Auto Email Report"] = [ { label: "Auto Email Reports", - url: docsUrl + "user/manual/en/setting-up/email/email-reports", + url: docsUrl + "user/manual/en/setting-up/email/auto-email-reports", }, ]; @@ -188,14 +208,7 @@ frappe.help.help_links["Form/Print Settings"] = [ frappe.help.help_links["print-format-builder"] = [ { label: "Print Format Builder", - url: docsUrl + "user/manual/en/setting-up/print/print-settings", - }, -]; - -frappe.help.help_links["List/Print Heading"] = [ - { - label: "Print Heading", - url: docsUrl + "user/manual/en/setting-up/print/print-headings", + url: docsUrl + "user/manual/en/setting-up/print/print-format-builder", }, ]; @@ -300,7 +313,7 @@ frappe.help.help_links["List/Sales Order"] = [ }, { label: "Recurring Sales Order", - url: docsUrl + "user/manual/en/accounts/recurring-orders-and-invoices", + url: docsUrl + "user/manual/en/accounts/articles/recurring-orders-and-invoices", }, { label: "Applying Discount", @@ -315,7 +328,7 @@ frappe.help.help_links["Form/Sales Order"] = [ }, { label: "Recurring Sales Order", - url: docsUrl + "user/manual/en/accounts/recurring-orders-and-invoices", + url: docsUrl + "user/manual/en/accounts/articles/recurring-orders-and-invoices", }, { label: "Applying Discount", @@ -344,14 +357,14 @@ frappe.help.help_links["Form/Sales Order"] = [ frappe.help.help_links["Form/Product Bundle"] = [ { label: "Product Bundle", - url: docsUrl + "user/manual/en/selling/setup/product-bundle", + url: docsUrl + "user/manual/en/selling/product-bundle", }, ]; frappe.help.help_links["Form/Selling Settings"] = [ { label: "Selling Settings", - url: docsUrl + "user/manual/en/selling/setup/selling-settings", + url: docsUrl + "user/manual/en/selling/selling-settings", }, ]; @@ -397,7 +410,7 @@ frappe.help.help_links["List/Purchase Order"] = [ }, { label: "Recurring Purchase Order", - url: docsUrl + "user/manual/en/accounts/recurring-orders-and-invoices", + url: docsUrl + "user/manual/en/accounts/articles/recurring-orders-and-invoices", }, ]; @@ -420,7 +433,7 @@ frappe.help.help_links["Form/Purchase Order"] = [ }, { label: "Recurring Purchase Order", - url: docsUrl + "user/manual/en/accounts/recurring-orders-and-invoices", + url: docsUrl + "user/manual/en/accounts/articles/recurring-orders-and-invoices", }, { label: "Subcontracting", @@ -435,24 +448,17 @@ frappe.help.help_links["List/Purchase Taxes and Charges Template"] = [ }, ]; -frappe.help.help_links["List/POS Profile"] = [ - { - label: "POS Profile", - url: docsUrl + "user/manual/en/setting-up/pos-setting", - }, -]; - frappe.help.help_links["List/Price List"] = [ { label: "Price List", - url: docsUrl + "user/manual/en/setting-up/price-lists", + url: docsUrl + "user/manual/en/stock/price-lists", }, ]; frappe.help.help_links["List/Authorization Rule"] = [ { label: "Authorization Rule", - url: docsUrl + "user/manual/en/setting-up/authorization-rule", + url: docsUrl + "user/manual/en/customize-erpnext/authorization-rule", }, ]; @@ -468,27 +474,14 @@ frappe.help.help_links["List/Stock Reconciliation"] = [ label: "Stock Reconciliation", url: docsUrl + - "user/manual/en/setting-up/stock-reconciliation-for-non-serialized-item", + "user/manual/en/stock/stock-reconciliation", }, ]; frappe.help.help_links["Tree/Territory"] = [ { label: "Territory", - url: docsUrl + "user/manual/en/setting-up/territory", - }, -]; - -frappe.help.help_links["Form/Dropbox Backup"] = [ - { - label: "Dropbox Backup", - url: docsUrl + "user/manual/en/setting-up/third-party-backups", - }, - { - label: "Setting Up Dropbox Backup", - url: - docsUrl + - "user/manual/en/setting-up/articles/setting-up-dropbox-backups", + url: docsUrl + "user/manual/en/selling/territory", }, ]; @@ -501,12 +494,6 @@ frappe.help.help_links["List/Company"] = [ label: "Company", url: docsUrl + "user/manual/en/setting-up/company-setup", }, - { - label: "Managing Multiple Companies", - url: - docsUrl + - "user/manual/en/setting-up/articles/managing-multiple-companies", - }, { label: "Delete All Related Transactions for a Company", url: @@ -517,21 +504,6 @@ frappe.help.help_links["List/Company"] = [ //Accounts -frappe.help.help_links["modules/Accounts"] = [ - { - label: "Introduction to Accounts", - url: docsUrl + "user/manual/en/accounts/", - }, - { - label: "Chart of Accounts", - url: docsUrl + "user/manual/en/accounts/chart-of-accounts.html", - }, - { - label: "Multi Currency Accounting", - url: docsUrl + "user/manual/en/accounts/multi-currency-accounting", - }, -]; - frappe.help.help_links["Tree/Account"] = [ { label: "Chart of Accounts", @@ -552,7 +524,7 @@ frappe.help.help_links["Form/Sales Invoice"] = [ }, { label: "Accounts Opening Balance", - url: docsUrl + "user/manual/en/accounts/opening-accounts", + url: docsUrl + "user/manual/en/accounts/opening-balance", }, { label: "Sales Return", @@ -560,7 +532,7 @@ frappe.help.help_links["Form/Sales Invoice"] = [ }, { label: "Recurring Sales Invoice", - url: docsUrl + "user/manual/en/accounts/recurring-orders-and-invoices", + url: docsUrl + "user/manual/en/accounts/articles/recurring-orders-and-invoices", }, ]; @@ -571,7 +543,7 @@ frappe.help.help_links["List/Sales Invoice"] = [ }, { label: "Accounts Opening Balance", - url: docsUrl + "user/manual/en/accounts/opening-accounts", + url: docsUrl + "user/manual/en/accounts/opening-balances", }, { label: "Sales Return", @@ -579,21 +551,28 @@ frappe.help.help_links["List/Sales Invoice"] = [ }, { label: "Recurring Sales Invoice", - url: docsUrl + "user/manual/en/accounts/recurring-orders-and-invoices", + url: docsUrl + "user/manual/en/accounts/articles/recurring-orders-and-invoices", }, ]; -frappe.help.help_links["pos"] = [ +frappe.help.help_links["point-of-sale"] = [ { label: "Point of Sale Invoice", - url: docsUrl + "user/manual/en/accounts/point-of-sale-pos-invoice", + url: docsUrl + "user/manual/en/accounts/point-of-sales", }, ]; frappe.help.help_links["List/POS Profile"] = [ { label: "Point of Sale Profile", - url: docsUrl + "user/manual/en/setting-up/pos-setting", + url: docsUrl + "user/manual/en/accounts/pos-profile", + }, +]; + +frappe.help.help_links["Form/POS Profile"] = [ + { + label: "POS Profile", + url: docsUrl + "user/manual/en/accounts/pos-profile", }, ]; @@ -604,11 +583,11 @@ frappe.help.help_links["List/Purchase Invoice"] = [ }, { label: "Accounts Opening Balance", - url: docsUrl + "user/manual/en/accounts/opening-accounts", + url: docsUrl + "user/manual/en/accounts/opening-balance", }, { label: "Recurring Purchase Invoice", - url: docsUrl + "user/manual/en/accounts/recurring-orders-and-invoices", + url: docsUrl + "user/manual/en/accounts/articles/recurring-orders-and-invoices", }, ]; @@ -623,7 +602,7 @@ frappe.help.help_links["List/Journal Entry"] = [ }, { label: "Accounts Opening Balance", - url: docsUrl + "user/manual/en/accounts/opening-accounts", + url: docsUrl + "user/manual/en/accounts/opening-balance", }, ]; @@ -644,7 +623,7 @@ frappe.help.help_links["List/Payment Request"] = [ frappe.help.help_links["List/Asset"] = [ { label: "Managing Fixed Assets", - url: docsUrl + "user/manual/en/accounts/opening-balance/fixed_assets", + url: docsUrl + "user/manual/en/asset", }, ]; @@ -659,6 +638,8 @@ frappe.help.help_links["Tree/Cost Center"] = [ { label: "Budgeting", url: docsUrl + "user/manual/en/accounts/budgeting" }, ]; +//Stock + frappe.help.help_links["List/Item"] = [ { label: "Item", url: docsUrl + "user/manual/en/stock/item" }, { @@ -676,7 +657,7 @@ frappe.help.help_links["List/Item"] = [ }, { label: "Managing Fixed Assets", - url: docsUrl + "user/manual/en/accounts/opening-balance/fixed_assets", + url: docsUrl + "user/manual/en/asset", }, { label: "Item Codification", @@ -711,7 +692,7 @@ frappe.help.help_links["Form/Item"] = [ }, { label: "Managing Fixed Assets", - url: docsUrl + "user/manual/en/accounts/opening-balance/fixed_assets", + url: docsUrl + "user/manual/en/asset", }, { label: "Item Codification", @@ -771,10 +752,6 @@ frappe.help.help_links["Form/Delivery Note"] = [ url: docsUrl + "user/manual/en/stock/articles/track-items-using-barcode", }, - { - label: "Subcontracting", - url: docsUrl + "user/manual/en/manufacturing/subcontracting", - }, ]; frappe.help.help_links["List/Installation Note"] = [ @@ -784,21 +761,10 @@ frappe.help.help_links["List/Installation Note"] = [ }, ]; -frappe.help.help_links["Tree"] = [ - { - label: "Managing Tree Structure Masters", - url: - docsUrl + - "user/manual/en/setting-up/articles/managing-tree-structure-masters", - }, -]; - frappe.help.help_links["List/Budget"] = [ { label: "Budgeting", url: docsUrl + "user/manual/en/accounts/budgeting" }, ]; -//Stock - frappe.help.help_links["List/Material Request"] = [ { label: "Material Request", @@ -861,6 +827,10 @@ frappe.help.help_links["Form/Serial No"] = [ { label: "Serial No", url: docsUrl + "user/manual/en/stock/serial-no" }, ]; +frappe.help.help_links["List/Batch"] = [ + { label: "Batch", url: docsUrl + "user/manual/en/stock/batch" }, +]; + frappe.help.help_links["Form/Batch"] = [ { label: "Batch", url: docsUrl + "user/manual/en/stock/batch" }, ]; @@ -868,35 +838,35 @@ frappe.help.help_links["Form/Batch"] = [ frappe.help.help_links["Form/Packing Slip"] = [ { label: "Packing Slip", - url: docsUrl + "user/manual/en/stock/tools/packing-slip", + url: docsUrl + "user/manual/en/stock/packing-slip", }, ]; frappe.help.help_links["Form/Quality Inspection"] = [ { label: "Quality Inspection", - url: docsUrl + "user/manual/en/stock/tools/quality-inspection", + url: docsUrl + "user/manual/en/stock/quality-inspection", }, ]; frappe.help.help_links["Form/Landed Cost Voucher"] = [ { label: "Landed Cost Voucher", - url: docsUrl + "user/manual/en/stock/tools/landed-cost-voucher", + url: docsUrl + "user/manual/en/stock/landed-cost-voucher", }, ]; frappe.help.help_links["Tree/Item Group"] = [ { label: "Item Group", - url: docsUrl + "user/manual/en/stock/setup/item-group", + url: docsUrl + "user/manual/en/stock/item-group", }, ]; frappe.help.help_links["Form/Item Attribute"] = [ { label: "Item Attribute", - url: docsUrl + "user/manual/en/stock/setup/item-attribute", + url: docsUrl + "user/manual/en/stock/item-attribute", }, ]; @@ -911,7 +881,7 @@ frappe.help.help_links["Form/UOM"] = [ frappe.help.help_links["Form/Stock Reconciliation"] = [ { label: "Opening Stock Entry", - url: docsUrl + "user/manual/en/stock/opening-stock", + url: docsUrl + "user/manual/en/stock/stock-reconciliation", }, ]; @@ -938,13 +908,13 @@ frappe.help.help_links["Form/Newsletter"] = [ ]; frappe.help.help_links["Form/Campaign"] = [ - { label: "Campaign", url: docsUrl + "user/manual/en/CRM/setup/campaign" }, + { label: "Campaign", url: docsUrl + "user/manual/en/CRM/campaign" }, ]; frappe.help.help_links["Tree/Sales Person"] = [ { label: "Sales Person", - url: docsUrl + "user/manual/en/CRM/setup/sales-person", + url: docsUrl + "user/manual/en/CRM/sales-person", }, ]; @@ -953,30 +923,13 @@ frappe.help.help_links["Form/Sales Person"] = [ label: "Sales Person Target", url: docsUrl + - "user/manual/en/selling/setup/sales-person-target-allocation", + "user/manual/en/selling/sales-person-target-allocation", }, -]; - -//Support - -frappe.help.help_links["List/Feedback Trigger"] = [ { - label: "Feedback Trigger", - url: docsUrl + "user/manual/en/setting-up/feedback/setting-up-feedback", - }, -]; - -frappe.help.help_links["List/Feedback Request"] = [ - { - label: "Feedback Request", - url: docsUrl + "user/manual/en/setting-up/feedback/submit-feedback", - }, -]; - -frappe.help.help_links["List/Feedback Request"] = [ - { - label: "Feedback Request", - url: docsUrl + "user/manual/en/setting-up/feedback/submit-feedback", + label: "Sales Person in Transactions", + url: + docsUrl + + "user/manual/en/selling/articles/sales-persons-in-the-sales-transactions", }, ]; @@ -1019,7 +972,7 @@ frappe.help.help_links["Form/Operation"] = [ frappe.help.help_links["Form/BOM Update Tool"] = [ { label: "BOM Update Tool", - url: docsUrl + "user/manual/en/manufacturing/tools/bom-update-tool", + url: docsUrl + "user/manual/en/manufacturing/bom-update-tool", }, ]; @@ -1036,7 +989,7 @@ frappe.help.help_links["Form/Customize Form"] = [ }, ]; -frappe.help.help_links["Form/Custom Field"] = [ +frappe.help.help_links["List/Custom Field"] = [ { label: "Custom Field", url: docsUrl + "user/manual/en/customize-erpnext/custom-field", diff --git a/erpnext/public/js/hierarchy_chart/hierarchy_chart_desktop.js b/erpnext/public/js/hierarchy_chart/hierarchy_chart_desktop.js index 62867327537..831626aa915 100644 --- a/erpnext/public/js/hierarchy_chart/hierarchy_chart_desktop.js +++ b/erpnext/public/js/hierarchy_chart/hierarchy_chart_desktop.js @@ -63,7 +63,7 @@ erpnext.HierarchyChart = class { }); node.parent.append(node_card); - node.$link = $(`#${node.id}`); + node.$link = $(`[id="${node.id}"]`); } show() { @@ -223,7 +223,7 @@ erpnext.HierarchyChart = class { let node = undefined; $.each(r.message, (_i, data) => { - if ($(`#${data.id}`).length) + if ($(`[id="${data.id}"]`).length) return; node = new me.Node({ @@ -263,7 +263,7 @@ erpnext.HierarchyChart = class { this.refresh_connectors(node.parent_id); // rebuild incoming connections - let grandparent = $(`#${node.parent_id}`).attr('data-parent'); + let grandparent = $(`[id="${node.parent_id}"]`).attr('data-parent'); this.refresh_connectors(grandparent); } @@ -282,7 +282,7 @@ erpnext.HierarchyChart = class { show_active_path(node) { // mark node parent on active path - $(`#${node.parent_id}`).addClass('active-path'); + $(`[id="${node.parent_id}"]`).addClass('active-path'); } load_children(node, deep=false) { @@ -317,7 +317,7 @@ erpnext.HierarchyChart = class { render_child_nodes(node, child_nodes) { const last_level = this.$hierarchy.find('.level:last').index(); - const current_level = $(`#${node.id}`).parent().parent().parent().index(); + const current_level = $(`[id="${node.id}"]`).parent().parent().parent().index(); if (last_level === current_level) { this.$hierarchy.append(` @@ -334,10 +334,12 @@ erpnext.HierarchyChart = class { if (child_nodes) { $.each(child_nodes, (_i, data) => { - this.add_node(node, data); - setTimeout(() => { - this.add_connector(node.id, data.id); - }, 250); + if (!$(`[id="${data.id}"]`).length) { + this.add_node(node, data); + setTimeout(() => { + this.add_connector(node.id, data.id); + }, 250); + } }); } } @@ -382,7 +384,7 @@ erpnext.HierarchyChart = class { node.$children = $('
    '); const last_level = this.$hierarchy.find('.level:last').index(); - const node_level = $(`#${node.id}`).parent().parent().parent().index(); + const node_level = $(`[id="${node.id}"]`).parent().parent().parent().index(); if (last_level === node_level) { this.$hierarchy.append(` @@ -489,7 +491,7 @@ erpnext.HierarchyChart = class { set_path_attributes(path, parent_id, child_id) { path.setAttribute("data-parent", parent_id); path.setAttribute("data-child", child_id); - const parent = $(`#${parent_id}`); + const parent = $(`[id="${parent_id}"]`); if (parent.hasClass('active')) { path.setAttribute("class", "active-connector"); @@ -513,7 +515,7 @@ erpnext.HierarchyChart = class { } collapse_previous_level_nodes(node) { - let node_parent = $(`#${node.parent_id}`); + let node_parent = $(`[id="${node.parent_id}"]`); let previous_level_nodes = node_parent.parent().parent().children('li'); let node_card = undefined; @@ -545,7 +547,7 @@ erpnext.HierarchyChart = class { setup_node_click_action(node) { let me = this; - let node_element = $(`#${node.id}`); + let node_element = $(`[id="${node.id}"]`); node_element.click(function() { const is_sibling = me.selected_node.parent_id === node.parent_id; @@ -563,7 +565,7 @@ erpnext.HierarchyChart = class { } setup_edit_node_action(node) { - let node_element = $(`#${node.id}`); + let node_element = $(`[id="${node.id}"]`); let me = this; node_element.find('.btn-edit-node').click(function() { @@ -572,7 +574,7 @@ erpnext.HierarchyChart = class { } remove_levels_after_node(node) { - let level = $(`#${node.id}`).parent().parent().parent().index(); + let level = $(`[id="${node.id}"]`).parent().parent().parent().index(); level = $('.hierarchy > li:eq('+ level + ')'); level.nextAll('li').remove(); @@ -595,7 +597,7 @@ erpnext.HierarchyChart = class { const parent = $(path).data('parent'); const child = $(path).data('child'); - if ($(`#${parent}`).length && $(`#${child}`).length) + if ($(`[id="${parent}"]`).length && $(`[id="${child}"]`).length) return; $(path).remove(); diff --git a/erpnext/public/js/hierarchy_chart/hierarchy_chart_mobile.js b/erpnext/public/js/hierarchy_chart/hierarchy_chart_mobile.js index b1a88795572..0a8ba78f643 100644 --- a/erpnext/public/js/hierarchy_chart/hierarchy_chart_mobile.js +++ b/erpnext/public/js/hierarchy_chart/hierarchy_chart_mobile.js @@ -54,7 +54,7 @@ erpnext.HierarchyChartMobile = class { }); node.parent.append(node_card); - node.$link = $(`#${node.id}`); + node.$link = $(`[id="${node.id}"]`); node.$link.addClass('mobile-node'); } @@ -184,7 +184,7 @@ erpnext.HierarchyChartMobile = class { this.refresh_connectors(node.parent_id, node.id); // rebuild incoming connections of parent - let grandparent = $(`#${node.parent_id}`).attr('data-parent'); + let grandparent = $(`[id="${node.parent_id}"]`).attr('data-parent'); this.refresh_connectors(grandparent, node.parent_id); } @@ -221,7 +221,7 @@ erpnext.HierarchyChartMobile = class { show_active_path(node) { // mark node parent on active path - $(`#${node.parent_id}`).addClass('active-path'); + $(`[id="${node.parent_id}"]`).addClass('active-path'); } load_children(node) { @@ -256,7 +256,7 @@ erpnext.HierarchyChartMobile = class { if (child_nodes) { $.each(child_nodes, (_i, data) => { this.add_node(node, data); - $(`#${data.id}`).addClass('active-child'); + $(`[id="${data.id}"]`).addClass('active-child'); setTimeout(() => { this.add_connector(node.id, data.id); @@ -293,9 +293,9 @@ erpnext.HierarchyChartMobile = class { let connector = undefined; - if ($(`#${parent_id}`).hasClass('active')) { + if ($(`[id="${parent_id}"]`).hasClass('active')) { connector = this.get_connector_for_active_node(parent_node, child_node); - } else if ($(`#${parent_id}`).hasClass('active-path')) { + } else if ($(`[id="${parent_id}"]`).hasClass('active-path')) { connector = this.get_connector_for_collapsed_node(parent_node, child_node); } @@ -351,7 +351,7 @@ erpnext.HierarchyChartMobile = class { set_path_attributes(path, parent_id, child_id) { path.setAttribute("data-parent", parent_id); path.setAttribute("data-child", child_id); - const parent = $(`#${parent_id}`); + const parent = $(`[id="${parent_id}"]`); if (parent.hasClass('active')) { path.setAttribute("class", "active-connector"); @@ -374,7 +374,7 @@ erpnext.HierarchyChartMobile = class { setup_node_click_action(node) { let me = this; - let node_element = $(`#${node.id}`); + let node_element = $(`[id="${node.id}"]`); node_element.click(function() { let el = undefined; @@ -398,7 +398,7 @@ erpnext.HierarchyChartMobile = class { } setup_edit_node_action(node) { - let node_element = $(`#${node.id}`); + let node_element = $(`[id="${node.id}"]`); let me = this; node_element.find('.btn-edit-node').click(function() { @@ -512,7 +512,7 @@ erpnext.HierarchyChartMobile = class { } remove_levels_after_node(node) { - let level = $(`#${node.id}`).parent().parent().index(); + let level = $(`[id="${node.id}"]`).parent().parent().index(); level = $('.hierarchy-mobile > li:eq('+ level + ')'); level.nextAll('li').remove(); @@ -533,7 +533,7 @@ erpnext.HierarchyChartMobile = class { const parent = $(path).data('parent'); const child = $(path).data('child'); - if ($(`#${parent}`).length && $(`#${child}`).length) + if ($(`[id="${parent}"]`).length && $(`[id="${child}"]`).length) return; $(path).remove(); diff --git a/erpnext/public/js/hub/PageContainer.vue b/erpnext/public/js/hub/PageContainer.vue deleted file mode 100644 index 54c359766d3..00000000000 --- a/erpnext/public/js/hub/PageContainer.vue +++ /dev/null @@ -1,119 +0,0 @@ - - - diff --git a/erpnext/public/js/hub/Sidebar.vue b/erpnext/public/js/hub/Sidebar.vue deleted file mode 100644 index 66c291ec52f..00000000000 --- a/erpnext/public/js/hub/Sidebar.vue +++ /dev/null @@ -1,110 +0,0 @@ - - diff --git a/erpnext/public/js/hub/components/CommentInput.vue b/erpnext/public/js/hub/components/CommentInput.vue deleted file mode 100644 index 31562c7a284..00000000000 --- a/erpnext/public/js/hub/components/CommentInput.vue +++ /dev/null @@ -1,39 +0,0 @@ - - diff --git a/erpnext/public/js/hub/components/DetailHeaderItem.vue b/erpnext/public/js/hub/components/DetailHeaderItem.vue deleted file mode 100644 index a6c5f066f28..00000000000 --- a/erpnext/public/js/hub/components/DetailHeaderItem.vue +++ /dev/null @@ -1,26 +0,0 @@ - - - diff --git a/erpnext/public/js/hub/components/DetailView.vue b/erpnext/public/js/hub/components/DetailView.vue deleted file mode 100644 index 942c1ebdb34..00000000000 --- a/erpnext/public/js/hub/components/DetailView.vue +++ /dev/null @@ -1,86 +0,0 @@ - - - - - diff --git a/erpnext/public/js/hub/components/EmptyState.vue b/erpnext/public/js/hub/components/EmptyState.vue deleted file mode 100644 index e3a33a08306..00000000000 --- a/erpnext/public/js/hub/components/EmptyState.vue +++ /dev/null @@ -1,50 +0,0 @@ - - - - - diff --git a/erpnext/public/js/hub/components/Image.vue b/erpnext/public/js/hub/components/Image.vue deleted file mode 100644 index 9acf4210322..00000000000 --- a/erpnext/public/js/hub/components/Image.vue +++ /dev/null @@ -1,40 +0,0 @@ - - diff --git a/erpnext/public/js/hub/components/ItemCard.vue b/erpnext/public/js/hub/components/ItemCard.vue deleted file mode 100644 index 675ad86645b..00000000000 --- a/erpnext/public/js/hub/components/ItemCard.vue +++ /dev/null @@ -1,142 +0,0 @@ - - - - - diff --git a/erpnext/public/js/hub/components/ItemCardsContainer.vue b/erpnext/public/js/hub/components/ItemCardsContainer.vue deleted file mode 100644 index 0a20bcdc636..00000000000 --- a/erpnext/public/js/hub/components/ItemCardsContainer.vue +++ /dev/null @@ -1,62 +0,0 @@ - - - - - diff --git a/erpnext/public/js/hub/components/ItemListCard.vue b/erpnext/public/js/hub/components/ItemListCard.vue deleted file mode 100644 index 7f6fb77d76e..00000000000 --- a/erpnext/public/js/hub/components/ItemListCard.vue +++ /dev/null @@ -1,21 +0,0 @@ - - diff --git a/erpnext/public/js/hub/components/NotificationMessage.vue b/erpnext/public/js/hub/components/NotificationMessage.vue deleted file mode 100644 index c26672635c3..00000000000 --- a/erpnext/public/js/hub/components/NotificationMessage.vue +++ /dev/null @@ -1,38 +0,0 @@ - - - - - diff --git a/erpnext/public/js/hub/components/Rating.vue b/erpnext/public/js/hub/components/Rating.vue deleted file mode 100644 index 33290b8e202..00000000000 --- a/erpnext/public/js/hub/components/Rating.vue +++ /dev/null @@ -1,16 +0,0 @@ - - - diff --git a/erpnext/public/js/hub/components/ReviewArea.vue b/erpnext/public/js/hub/components/ReviewArea.vue deleted file mode 100644 index aa83bb0e465..00000000000 --- a/erpnext/public/js/hub/components/ReviewArea.vue +++ /dev/null @@ -1,140 +0,0 @@ - - diff --git a/erpnext/public/js/hub/components/ReviewTimelineItem.vue b/erpnext/public/js/hub/components/ReviewTimelineItem.vue deleted file mode 100644 index d0e83f3b1cd..00000000000 --- a/erpnext/public/js/hub/components/ReviewTimelineItem.vue +++ /dev/null @@ -1,53 +0,0 @@ - - - diff --git a/erpnext/public/js/hub/components/SearchInput.vue b/erpnext/public/js/hub/components/SearchInput.vue deleted file mode 100644 index 4b1ce6e4ef9..00000000000 --- a/erpnext/public/js/hub/components/SearchInput.vue +++ /dev/null @@ -1,26 +0,0 @@ - - - diff --git a/erpnext/public/js/hub/components/SectionHeader.vue b/erpnext/public/js/hub/components/SectionHeader.vue deleted file mode 100644 index 05a2f838a0a..00000000000 --- a/erpnext/public/js/hub/components/SectionHeader.vue +++ /dev/null @@ -1,3 +0,0 @@ - diff --git a/erpnext/public/js/hub/components/TimelineItem.vue b/erpnext/public/js/hub/components/TimelineItem.vue deleted file mode 100644 index d13c842beb8..00000000000 --- a/erpnext/public/js/hub/components/TimelineItem.vue +++ /dev/null @@ -1,9 +0,0 @@ -/* Saving this for later */ - diff --git a/erpnext/public/js/hub/components/edit_details_dialog.js b/erpnext/public/js/hub/components/edit_details_dialog.js deleted file mode 100644 index 97c5f83a13a..00000000000 --- a/erpnext/public/js/hub/components/edit_details_dialog.js +++ /dev/null @@ -1,41 +0,0 @@ -function edit_details_dialog(params) { - let dialog = new frappe.ui.Dialog({ - title: __('Update Details'), - fields: [ - { - label: 'Item Name', - fieldname: 'item_name', - fieldtype: 'Data', - default: params.defaults.item_name, - reqd: 1 - }, - { - label: 'Hub Category', - fieldname: 'hub_category', - fieldtype: 'Autocomplete', - default: params.defaults.hub_category, - options: [], - reqd: 1 - }, - { - label: 'Description', - fieldname: 'description', - fieldtype: 'Text', - default: params.defaults.description, - options: [], - reqd: 1 - } - ], - primary_action_label: params.primary_action.label || __('Update Details'), - primary_action: params.primary_action.fn - }); - - hub.call('get_categories').then(categories => { - categories = categories.map(d => d.name); - dialog.fields_dict.hub_category.set_data(categories); - }); - - return dialog; -} - -export { edit_details_dialog }; diff --git a/erpnext/public/js/hub/components/item_publish_dialog.js b/erpnext/public/js/hub/components/item_publish_dialog.js deleted file mode 100644 index 08de5b30b6c..00000000000 --- a/erpnext/public/js/hub/components/item_publish_dialog.js +++ /dev/null @@ -1,39 +0,0 @@ -function ItemPublishDialog(primary_action, secondary_action) { - let dialog = new frappe.ui.Dialog({ - title: __('Edit Publishing Details'), - fields: [ - { - label: __('Item Code'), - fieldname: 'item_code', - fieldtype: 'Data', - read_only: 1 - }, - { - label: __('Hub Category'), - fieldname: 'hub_category', - fieldtype: 'Autocomplete', - options: [], - reqd: 1 - }, - { - label: __('Images'), - fieldname: 'image_list', - fieldtype: 'MultiSelect', - options: [], - reqd: 1 - } - ], - primary_action_label: primary_action.label || __('Set Details'), - primary_action: primary_action.fn, - secondary_action: secondary_action.fn - }); - - hub.call('get_categories').then(categories => { - categories = categories.map(d => d.name); - dialog.fields_dict.hub_category.set_data(categories); - }); - - return dialog; -} - -export { ItemPublishDialog }; diff --git a/erpnext/public/js/hub/components/profile_dialog.js b/erpnext/public/js/hub/components/profile_dialog.js deleted file mode 100644 index 8e3abc37eb8..00000000000 --- a/erpnext/public/js/hub/components/profile_dialog.js +++ /dev/null @@ -1,56 +0,0 @@ -const ProfileDialog = (title = __('Edit Profile'), action={}) => { - const fields = [ - { - fieldtype: 'Link', - fieldname: 'company', - label: __('Company'), - options: 'Company' - }, - { - fieldtype: 'Read Only', - fieldname: 'email', - label: __('Email') - }, - { - label: __('About your company'), - fieldname: 'company_description', - fieldtype: 'Text' - } - ]; - - let dialog = new frappe.ui.Dialog({ - title: title, - fields: fields, - primary_action_label: action.label || __('Update'), - primary_action: () => { - const form_values = dialog.get_values(); - let values_filled = true; - - // TODO: Say "we notice that the company description and logo isn't set. Please set them in master." - // Only then allow to register - - const mandatory_fields = ['company', 'company_description']; - mandatory_fields.forEach(field => { - const value = form_values[field]; - if (!value) { - dialog.set_df_property(field, 'reqd', 1); - values_filled = false; - } - }); - if (!values_filled) return; - - action.on_submit(form_values); - } - }); - - // Post create - const default_company = frappe.defaults.get_default('company'); - dialog.set_value('company', default_company); - dialog.set_value('email', frappe.session.user); - - return dialog; -} - -export { - ProfileDialog -} diff --git a/erpnext/public/js/hub/components/reviews.js b/erpnext/public/js/hub/components/reviews.js deleted file mode 100644 index e34d68038f7..00000000000 --- a/erpnext/public/js/hub/components/reviews.js +++ /dev/null @@ -1,80 +0,0 @@ -function get_review_html(review) { - let username = review.username || review.user || __("Anonymous"); - - let image_html = review.user_image - ? `
    ` - : `
    ${frappe.get_abbr(username)}
    ` - - let edit_html = review.own - ? ` -
    - - ${'data.edit'} - -
    ` - : ''; - - let rating_html = get_rating_html(review.rating); - - return get_timeline_item(review, image_html, edit_html, rating_html); -} - -function get_timeline_item(data, image_html, edit_html, rating_html) { - return `
    - -
    -
    -
    ${edit_html}
    - -
    - - ${image_html} - - -
    - - - ${data.username} - - - - - -
    -
    -
    -
    -

    - ${rating_html} -

    -
    ${data.subject}
    -

    - ${data.content} -

    -
    -
    -
    -
    -
    `; -} - -function get_rating_html(rating) { - let rating_html = ``; - for (var i = 0; i < 5; i++) { - let star_class = 'fa-star'; - if (i >= rating) star_class = 'fa-star-o'; - rating_html += ``; - } - return rating_html; -} - -export { - get_review_html, - get_rating_html -} diff --git a/erpnext/public/js/hub/hub_call.js b/erpnext/public/js/hub/hub_call.js deleted file mode 100644 index 5545a4935b3..00000000000 --- a/erpnext/public/js/hub/hub_call.js +++ /dev/null @@ -1,68 +0,0 @@ -frappe.provide('hub'); -frappe.provide('erpnext.hub'); - -erpnext.hub.cache = {}; -hub.call = function call_hub_method(method, args={}, clear_cache_on_event) { // eslint-disable-line - return new Promise((resolve, reject) => { - - // cache - const key = method + JSON.stringify(args); - if (erpnext.hub.cache[key]) { - resolve(erpnext.hub.cache[key]); - } - - // cache invalidation - const clear_cache = () => delete erpnext.hub.cache[key]; - - if (!clear_cache_on_event) { - invalidate_after_5_mins(clear_cache); - } else { - erpnext.hub.on(clear_cache_on_event, () => { - clear_cache(key); - }); - } - - let res; - if (hub.is_server) { - res = frappe.call({ - method: 'hub.hub.api.' + method, - args - }); - } else { - res = frappe.call({ - method: 'erpnext.hub_node.api.call_hub_method', - args: { - method, - params: args - } - }); - } - - res.then(r => { - if (r.message) { - const response = r.message; - if (response.error) { - frappe.throw({ - title: __('Marketplace Error'), - message: response.error - }); - } - - erpnext.hub.cache[key] = response; - erpnext.hub.trigger(`response:${key}`, { response }); - resolve(response); - } - reject(r); - - }).fail(reject); - }); -}; - -function invalidate_after_5_mins(clear_cache) { - // cache invalidation after 5 minutes - const timeout = 5 * 60 * 1000; - - setTimeout(() => { - clear_cache(); - }, timeout); -} diff --git a/erpnext/public/js/hub/hub_factory.js b/erpnext/public/js/hub/hub_factory.js deleted file mode 100644 index 9c67c1cf9f0..00000000000 --- a/erpnext/public/js/hub/hub_factory.js +++ /dev/null @@ -1,34 +0,0 @@ -frappe.provide('erpnext.hub'); - -frappe.views.MarketplaceFactory = class MarketplaceFactory extends frappe.views.Factory { - show() { - is_marketplace_disabled() - .then(disabled => { - if (disabled) { - frappe.show_not_found('Marketplace'); - return; - } - - if (frappe.pages.marketplace) { - frappe.container.change_to('marketplace'); - erpnext.hub.marketplace.refresh(); - } else { - this.make('marketplace'); - } - }); - } - - make(page_name) { - frappe.require('marketplace.bundle.js', () => { - erpnext.hub.marketplace = new erpnext.hub.Marketplace({ - parent: this.make_page(true, page_name) - }); - }); - } -}; - -function is_marketplace_disabled() { - return frappe.call({ - method: "erpnext.hub_node.doctype.marketplace_settings.marketplace_settings.is_marketplace_enabled" - }).then(r => r.message) -} diff --git a/erpnext/public/js/hub/marketplace.bundle.js b/erpnext/public/js/hub/marketplace.bundle.js deleted file mode 100644 index a1596e0043b..00000000000 --- a/erpnext/public/js/hub/marketplace.bundle.js +++ /dev/null @@ -1,225 +0,0 @@ -import Vue from 'vue/dist/vue.js'; -import './vue-plugins'; - -// components -import PageContainer from './PageContainer.vue'; -import Sidebar from './Sidebar.vue'; -import { ProfileDialog } from './components/profile_dialog'; - -// helpers -import './hub_call'; - -frappe.provide('hub'); -frappe.provide('erpnext.hub'); -frappe.provide('frappe.route'); - -frappe.utils.make_event_emitter(frappe.route); -frappe.utils.make_event_emitter(erpnext.hub); - -erpnext.hub.Marketplace = class Marketplace { - constructor({ parent }) { - this.$parent = $(parent); - this.page = parent.page; - - this.update_hub_settings().then(() => { - - this.setup_header(); - this.make_sidebar(); - this.make_body(); - this.setup_events(); - this.refresh(); - - if (!hub.is_server) { - if (!hub.is_seller_registered()) { - this.page.set_primary_action('Become a Seller', this.show_register_dialog.bind(this)) - } else { - this.page.set_secondary_action('Add Users', this.show_add_user_dialog.bind(this)); - } - } - }); - } - - setup_header() { - if (hub.is_server) return; - this.page.set_title(__('Marketplace')); - } - - setup_events() { - this.$parent.on('click', '[data-route]', (e) => { - const $target = $(e.currentTarget); - const route = $target.data().route; - frappe.set_route(route); - }); - - // generic action handler - this.$parent.on('click', '[data-action]', e => { - const $target = $(e.currentTarget); - const action = $target.data().action; - - if (action && this[action]) { - this[action].apply(this, $target); - } - }) - } - - make_sidebar() { - this.$sidebar = this.$parent.find('.layout-side-section').addClass('hidden-xs'); - - new Vue({ - el: $('
    ').appendTo(this.$sidebar)[0], - render: h => h(Sidebar) - }); - } - - make_body() { - this.$body = this.$parent.find('.layout-main-section'); - this.$page_container = $('
    ').appendTo(this.$body); - - new Vue({ - el: '.hub-page-container', - render: h => h(PageContainer) - }); - - if (!hub.is_server) { - erpnext.hub.on('seller-registered', () => { - this.page.clear_primary_action(); - }); - } - } - - refresh() { - - } - - show_register_dialog() { - if(frappe.session.user === 'Administrator') { - frappe.msgprint(__('You need to be a user other than Administrator with System Manager and Item Manager roles to register on Marketplace.')); - return; - } - - if (!is_subset(['System Manager', 'Item Manager'], frappe.user_roles)) { - frappe.msgprint(__('You need to be a user with System Manager and Item Manager roles to register on Marketplace.')); - return; - } - - this.register_dialog = ProfileDialog( - __('Become a Seller'), - { - label: __('Register'), - on_submit: this.register_marketplace.bind(this) - } - ); - - this.register_dialog.show(); - } - - register_marketplace({company, company_description}) { - frappe.call({ - method: 'erpnext.hub_node.api.register_marketplace', - args: { - company, - company_description - } - }).then((r) => { - if (r.message && r.message.ok) { - this.register_dialog.hide(); - - this.update_hub_settings() - .then(() => { - frappe.set_route('marketplace', 'publish'); - erpnext.hub.trigger('seller-registered'); - }); - } - }); - } - - show_add_user_dialog() { - if (!is_subset(['System Manager', 'Item Manager'], frappe.user_roles)) { - frappe.msgprint(__('You need to be a user with System Manager and Item Manager roles to add users to Marketplace.')); - return; - } - - this.get_unregistered_users() - .then(r => { - const user_list = r.message; - - const d = new frappe.ui.Dialog({ - title: __('Add Users to Marketplace'), - fields: [ - { - label: __('Users'), - fieldname: 'users', - fieldtype: 'MultiSelect', - reqd: 1, - get_data() { - return user_list; - } - } - ], - primary_action({ users }) { - const selected_users = users.split(',').map(d => d.trim()).filter(Boolean); - - if (!selected_users.every(user => user_list.includes(user))) { - d.set_df_property('users', 'description', __('Some emails are invalid')); - return; - } else { - d.set_df_property('users', 'description', ''); - } - - frappe.call('erpnext.hub_node.api.register_users', { - user_list: selected_users - }) - .then(r => { - d.hide(); - - if (r.message && r.message.length) { - frappe.show_alert(__('Added {0} users', [r.message.length])); - } - }); - } - }); - - d.show(); - }); - } - - get_unregistered_users() { - return frappe.call('erpnext.hub_node.api.get_unregistered_users') - } - - update_hub_settings() { - return hub.get_settings().then(doc => { - hub.settings = doc; - }); - } -} - -Object.assign(hub, { - is_seller_registered() { - return hub.settings.registered; - }, - - is_user_registered() { - return this.is_seller_registered() && hub.settings.users - .filter(hub_user => hub_user.user === frappe.session.user) - .length === 1; - }, - - get_settings() { - if (frappe.session.user === 'Guest') { - return Promise.resolve({ - registered: 0 - }); - } - return frappe.db.get_doc('Marketplace Settings'); - } -}); - -/** - * Returns true if list_a is subset of list_b - * @param {Array} list_a - * @param {Array} list_b - */ -function is_subset(list_a, list_b) { - return list_a.every(item => list_b.includes(item)); -} diff --git a/erpnext/public/js/hub/pages/Buying.vue b/erpnext/public/js/hub/pages/Buying.vue deleted file mode 100644 index ebf593aca4d..00000000000 --- a/erpnext/public/js/hub/pages/Buying.vue +++ /dev/null @@ -1,56 +0,0 @@ - - diff --git a/erpnext/public/js/hub/pages/Category.vue b/erpnext/public/js/hub/pages/Category.vue deleted file mode 100644 index 16d06018ff0..00000000000 --- a/erpnext/public/js/hub/pages/Category.vue +++ /dev/null @@ -1,76 +0,0 @@ - - - - - diff --git a/erpnext/public/js/hub/pages/FeaturedItems.vue b/erpnext/public/js/hub/pages/FeaturedItems.vue deleted file mode 100644 index 8380b2b2c0b..00000000000 --- a/erpnext/public/js/hub/pages/FeaturedItems.vue +++ /dev/null @@ -1,116 +0,0 @@ - - - - - diff --git a/erpnext/public/js/hub/pages/Home.vue b/erpnext/public/js/hub/pages/Home.vue deleted file mode 100644 index 8fe824566db..00000000000 --- a/erpnext/public/js/hub/pages/Home.vue +++ /dev/null @@ -1,114 +0,0 @@ - - - - - diff --git a/erpnext/public/js/hub/pages/Item.vue b/erpnext/public/js/hub/pages/Item.vue deleted file mode 100644 index 93002a7b27a..00000000000 --- a/erpnext/public/js/hub/pages/Item.vue +++ /dev/null @@ -1,356 +0,0 @@ - - - - - diff --git a/erpnext/public/js/hub/pages/Messages.vue b/erpnext/public/js/hub/pages/Messages.vue deleted file mode 100644 index 73506e99266..00000000000 --- a/erpnext/public/js/hub/pages/Messages.vue +++ /dev/null @@ -1,104 +0,0 @@ - - diff --git a/erpnext/public/js/hub/pages/NotFound.vue b/erpnext/public/js/hub/pages/NotFound.vue deleted file mode 100644 index 8901b97802d..00000000000 --- a/erpnext/public/js/hub/pages/NotFound.vue +++ /dev/null @@ -1,36 +0,0 @@ - - - - - diff --git a/erpnext/public/js/hub/pages/Publish.vue b/erpnext/public/js/hub/pages/Publish.vue deleted file mode 100644 index ecba4b1e5a8..00000000000 --- a/erpnext/public/js/hub/pages/Publish.vue +++ /dev/null @@ -1,212 +0,0 @@ - - - - - diff --git a/erpnext/public/js/hub/pages/PublishedItems.vue b/erpnext/public/js/hub/pages/PublishedItems.vue deleted file mode 100644 index cbb22164e6e..00000000000 --- a/erpnext/public/js/hub/pages/PublishedItems.vue +++ /dev/null @@ -1,74 +0,0 @@ - - - - - diff --git a/erpnext/public/js/hub/pages/SavedItems.vue b/erpnext/public/js/hub/pages/SavedItems.vue deleted file mode 100644 index 7007ddcf8e7..00000000000 --- a/erpnext/public/js/hub/pages/SavedItems.vue +++ /dev/null @@ -1,116 +0,0 @@ - - - - - diff --git a/erpnext/public/js/hub/pages/Search.vue b/erpnext/public/js/hub/pages/Search.vue deleted file mode 100644 index c10841e9848..00000000000 --- a/erpnext/public/js/hub/pages/Search.vue +++ /dev/null @@ -1,81 +0,0 @@ - - - - - diff --git a/erpnext/public/js/hub/pages/Seller.vue b/erpnext/public/js/hub/pages/Seller.vue deleted file mode 100644 index 3c9b800f4a0..00000000000 --- a/erpnext/public/js/hub/pages/Seller.vue +++ /dev/null @@ -1,201 +0,0 @@ - - - - - diff --git a/erpnext/public/js/hub/pages/SellerItems.vue b/erpnext/public/js/hub/pages/SellerItems.vue deleted file mode 100644 index 852fbaee3ff..00000000000 --- a/erpnext/public/js/hub/pages/SellerItems.vue +++ /dev/null @@ -1,57 +0,0 @@ - - - - - diff --git a/erpnext/public/js/hub/pages/Selling.vue b/erpnext/public/js/hub/pages/Selling.vue deleted file mode 100644 index 8743027885d..00000000000 --- a/erpnext/public/js/hub/pages/Selling.vue +++ /dev/null @@ -1,66 +0,0 @@ - - diff --git a/erpnext/public/js/hub/vue-plugins.js b/erpnext/public/js/hub/vue-plugins.js deleted file mode 100644 index 4912d684991..00000000000 --- a/erpnext/public/js/hub/vue-plugins.js +++ /dev/null @@ -1,58 +0,0 @@ -import Vue from 'vue/dist/vue.js'; - -// Global components -import ItemCardsContainer from './components/ItemCardsContainer.vue'; -import SectionHeader from './components/SectionHeader.vue'; -import SearchInput from './components/SearchInput.vue'; -import DetailView from './components/DetailView.vue'; -import DetailHeaderItem from './components/DetailHeaderItem.vue'; -import EmptyState from './components/EmptyState.vue'; -import Image from './components/Image.vue'; - -Vue.prototype.__ = window.__; -Vue.prototype.frappe = window.frappe; - -Vue.component('item-cards-container', ItemCardsContainer); -Vue.component('section-header', SectionHeader); -Vue.component('search-input', SearchInput); -Vue.component('detail-view', DetailView); -Vue.component('detail-header-item', DetailHeaderItem); -Vue.component('empty-state', EmptyState); -Vue.component('base-image', Image); - -Vue.directive('route', { - bind(el, binding) { - const route = binding.value; - if (!route) return; - el.classList.add('cursor-pointer'); - el.dataset.route = route; - el.addEventListener('click', () => frappe.set_route(route)); - }, - unbind(el) { - el.classList.remove('cursor-pointer'); - } -}); - -const handleImage = (el, src) => { - let img = new Image(); - // add loading class - el.src = ''; - el.classList.add('img-loading'); - - img.onload = () => { - // image loaded, remove loading class - el.classList.remove('img-loading'); - // set src - el.src = src; - } - img.onerror = () => { - el.classList.remove('img-loading'); - el.classList.add('no-image'); - el.src = null; - } - img.src = src; -} - -Vue.filter('striphtml', function (text) { - return strip_html(text || ''); -}); diff --git a/erpnext/public/js/utils.js b/erpnext/public/js/utils.js index e0610eb8c01..f0facdd3a10 100755 --- a/erpnext/public/js/utils.js +++ b/erpnext/public/js/utils.js @@ -709,14 +709,21 @@ erpnext.utils.map_current_doc = function(opts) { setters: opts.setters, get_query: opts.get_query, add_filters_group: 1, + allow_child_item_selection: opts.allow_child_item_selection, + child_fieldname: opts.child_fielname, + child_columns: opts.child_columns, + size: opts.size, action: function(selections, args) { let values = selections; - if(values.length === 0){ + if (values.length === 0) { frappe.msgprint(__("Please select {0}", [opts.source_doctype])) return; } opts.source_name = values; - opts.setters = args; + if (opts.allow_child_item_selection) { + // args contains filtered child docnames + opts.args = args; + } d.dialog.hide(); _map(); }, @@ -744,9 +751,13 @@ frappe.form.link_formatters['Item'] = function(value, doc) { } frappe.form.link_formatters['Employee'] = function(value, doc) { - if(doc && doc.employee_name && doc.employee_name !== value) { - return value? value + ': ' + doc.employee_name: doc.employee_name; + if (doc && value && doc.employee_name && doc.employee_name !== value && doc.employee === value) { + return value + ': ' + doc.employee_name; + } else if (!value && doc.doctype && doc.employee_name) { + // format blank value in child table + return doc.employee; } else { + // if value is blank in report view or project name and name are the same, return as is return value; } } diff --git a/erpnext/public/scss/shopping_cart.scss b/erpnext/public/scss/shopping_cart.scss index 490a7c4af73..fef1e76154f 100644 --- a/erpnext/public/scss/shopping_cart.scss +++ b/erpnext/public/scss/shopping_cart.scss @@ -31,6 +31,14 @@ body.product-page { .carousel-control-prev, .carousel-control-next { opacity: 1; + width: 8%; + + @media (max-width: 1200px) { + width: 10%; + } + @media (max-width: 768px) { + width: 15%; + } } .carousel-body { @@ -43,6 +51,8 @@ body.product-page { .carousel-content { max-width: 400px; + margin-left: 5rem; + margin-right: 5rem; } .card { diff --git a/erpnext/quality_management/doctype/non_conformance/non_conformance.py b/erpnext/quality_management/doctype/non_conformance/non_conformance.py index a4613fdaf6b..a2198f374ad 100644 --- a/erpnext/quality_management/doctype/non_conformance/non_conformance.py +++ b/erpnext/quality_management/doctype/non_conformance/non_conformance.py @@ -1,8 +1,6 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2020, Frappe Technologies Pvt. Ltd. and contributors # For license information, please see license.txt -from __future__ import unicode_literals # import frappe from frappe.model.document import Document diff --git a/erpnext/quality_management/doctype/non_conformance/test_non_conformance.py b/erpnext/quality_management/doctype/non_conformance/test_non_conformance.py index 759b117f9b0..3e94b35745c 100644 --- a/erpnext/quality_management/doctype/non_conformance/test_non_conformance.py +++ b/erpnext/quality_management/doctype/non_conformance/test_non_conformance.py @@ -1,7 +1,5 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2020, Frappe Technologies Pvt. Ltd. and Contributors # See license.txt -from __future__ import unicode_literals # import frappe import unittest diff --git a/erpnext/quality_management/doctype/quality_action/quality_action.py b/erpnext/quality_management/doctype/quality_action/quality_action.py index 646a0dfc2c8..87245f9a3f8 100644 --- a/erpnext/quality_management/doctype/quality_action/quality_action.py +++ b/erpnext/quality_management/doctype/quality_action/quality_action.py @@ -1,8 +1,6 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2018, Frappe and contributors # For license information, please see license.txt -from __future__ import unicode_literals from frappe.model.document import Document diff --git a/erpnext/quality_management/doctype/quality_action/test_quality_action.py b/erpnext/quality_management/doctype/quality_action/test_quality_action.py index 33229d4b451..fefa9dfe9cd 100644 --- a/erpnext/quality_management/doctype/quality_action/test_quality_action.py +++ b/erpnext/quality_management/doctype/quality_action/test_quality_action.py @@ -1,7 +1,5 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2018, Frappe and Contributors # See license.txt -from __future__ import unicode_literals import unittest diff --git a/erpnext/quality_management/doctype/quality_action_resolution/quality_action_resolution.py b/erpnext/quality_management/doctype/quality_action_resolution/quality_action_resolution.py index b456fb7e9a0..7ede3e4de00 100644 --- a/erpnext/quality_management/doctype/quality_action_resolution/quality_action_resolution.py +++ b/erpnext/quality_management/doctype/quality_action_resolution/quality_action_resolution.py @@ -1,8 +1,6 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2019, Frappe Technologies Pvt. Ltd. and contributors # For license information, please see license.txt -from __future__ import unicode_literals # import frappe from frappe.model.document import Document diff --git a/erpnext/quality_management/doctype/quality_feedback/quality_feedback.py b/erpnext/quality_management/doctype/quality_feedback/quality_feedback.py index 9189c282973..ec5d67f4f03 100644 --- a/erpnext/quality_management/doctype/quality_feedback/quality_feedback.py +++ b/erpnext/quality_management/doctype/quality_feedback/quality_feedback.py @@ -1,8 +1,6 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2019, Frappe Technologies Pvt. Ltd. and contributors # For license information, please see license.txt -from __future__ import unicode_literals import frappe from frappe.model.document import Document diff --git a/erpnext/quality_management/doctype/quality_feedback/test_quality_feedback.py b/erpnext/quality_management/doctype/quality_feedback/test_quality_feedback.py index 7a87c362446..fe36cc6e5b1 100644 --- a/erpnext/quality_management/doctype/quality_feedback/test_quality_feedback.py +++ b/erpnext/quality_management/doctype/quality_feedback/test_quality_feedback.py @@ -1,7 +1,5 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2019, Frappe Technologies Pvt. Ltd. and Contributors # See license.txt -from __future__ import unicode_literals import unittest diff --git a/erpnext/quality_management/doctype/quality_feedback_parameter/quality_feedback_parameter.py b/erpnext/quality_management/doctype/quality_feedback_parameter/quality_feedback_parameter.py index 9a21b263603..ff2c8415766 100644 --- a/erpnext/quality_management/doctype/quality_feedback_parameter/quality_feedback_parameter.py +++ b/erpnext/quality_management/doctype/quality_feedback_parameter/quality_feedback_parameter.py @@ -1,8 +1,6 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2019, Frappe Technologies Pvt. Ltd. and contributors # For license information, please see license.txt -from __future__ import unicode_literals # import frappe from frappe.model.document import Document diff --git a/erpnext/quality_management/doctype/quality_feedback_template/quality_feedback_template.py b/erpnext/quality_management/doctype/quality_feedback_template/quality_feedback_template.py index c6a520a3c59..4590f9d3a05 100644 --- a/erpnext/quality_management/doctype/quality_feedback_template/quality_feedback_template.py +++ b/erpnext/quality_management/doctype/quality_feedback_template/quality_feedback_template.py @@ -1,8 +1,6 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2019, Frappe Technologies Pvt. Ltd. and contributors # For license information, please see license.txt -from __future__ import unicode_literals # import frappe from frappe.model.document import Document diff --git a/erpnext/quality_management/doctype/quality_feedback_template/test_quality_feedback_template.py b/erpnext/quality_management/doctype/quality_feedback_template/test_quality_feedback_template.py index 1de58aae3ed..4b8bc0f0437 100644 --- a/erpnext/quality_management/doctype/quality_feedback_template/test_quality_feedback_template.py +++ b/erpnext/quality_management/doctype/quality_feedback_template/test_quality_feedback_template.py @@ -1,7 +1,5 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2019, Frappe Technologies Pvt. Ltd. and Contributors # See license.txt -from __future__ import unicode_literals import unittest diff --git a/erpnext/quality_management/doctype/quality_feedback_template_parameter/quality_feedback_template_parameter.py b/erpnext/quality_management/doctype/quality_feedback_template_parameter/quality_feedback_template_parameter.py index 44a6b014a0c..13e215f954a 100644 --- a/erpnext/quality_management/doctype/quality_feedback_template_parameter/quality_feedback_template_parameter.py +++ b/erpnext/quality_management/doctype/quality_feedback_template_parameter/quality_feedback_template_parameter.py @@ -1,8 +1,6 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2019, Frappe Technologies Pvt. Ltd. and contributors # For license information, please see license.txt -from __future__ import unicode_literals # import frappe from frappe.model.document import Document diff --git a/erpnext/quality_management/doctype/quality_goal/quality_goal.py b/erpnext/quality_management/doctype/quality_goal/quality_goal.py index 2888401782a..22ba81073d1 100644 --- a/erpnext/quality_management/doctype/quality_goal/quality_goal.py +++ b/erpnext/quality_management/doctype/quality_goal/quality_goal.py @@ -1,8 +1,6 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2018, Frappe and contributors # For license information, please see license.txt -from __future__ import unicode_literals from frappe.model.document import Document diff --git a/erpnext/quality_management/doctype/quality_goal/test_quality_goal.py b/erpnext/quality_management/doctype/quality_goal/test_quality_goal.py index 84240d227ea..67fdaca6d9b 100644 --- a/erpnext/quality_management/doctype/quality_goal/test_quality_goal.py +++ b/erpnext/quality_management/doctype/quality_goal/test_quality_goal.py @@ -1,7 +1,5 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2018, Frappe and Contributors # See license.txt -from __future__ import unicode_literals import unittest diff --git a/erpnext/quality_management/doctype/quality_goal_objective/quality_goal_objective.py b/erpnext/quality_management/doctype/quality_goal_objective/quality_goal_objective.py index c9c2c6e564c..eaa8db21563 100644 --- a/erpnext/quality_management/doctype/quality_goal_objective/quality_goal_objective.py +++ b/erpnext/quality_management/doctype/quality_goal_objective/quality_goal_objective.py @@ -1,8 +1,6 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2019, Frappe Technologies Pvt. Ltd. and contributors # For license information, please see license.txt -from __future__ import unicode_literals # import frappe from frappe.model.document import Document diff --git a/erpnext/quality_management/doctype/quality_meeting/quality_meeting.py b/erpnext/quality_management/doctype/quality_meeting/quality_meeting.py index 0ac0484399e..481b3c17f11 100644 --- a/erpnext/quality_management/doctype/quality_meeting/quality_meeting.py +++ b/erpnext/quality_management/doctype/quality_meeting/quality_meeting.py @@ -1,8 +1,6 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2018, Frappe and contributors # For license information, please see license.txt -from __future__ import unicode_literals from frappe.model.document import Document diff --git a/erpnext/quality_management/doctype/quality_meeting/test_quality_meeting.py b/erpnext/quality_management/doctype/quality_meeting/test_quality_meeting.py index e57256d2896..910b8a1130a 100644 --- a/erpnext/quality_management/doctype/quality_meeting/test_quality_meeting.py +++ b/erpnext/quality_management/doctype/quality_meeting/test_quality_meeting.py @@ -1,7 +1,5 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2018, Frappe and Contributors # See license.txt -from __future__ import unicode_literals import unittest diff --git a/erpnext/quality_management/doctype/quality_meeting_agenda/quality_meeting_agenda.py b/erpnext/quality_management/doctype/quality_meeting_agenda/quality_meeting_agenda.py index 5e4d9ff37a7..c2f5b3f17c1 100644 --- a/erpnext/quality_management/doctype/quality_meeting_agenda/quality_meeting_agenda.py +++ b/erpnext/quality_management/doctype/quality_meeting_agenda/quality_meeting_agenda.py @@ -1,8 +1,6 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2019, Frappe Technologies Pvt. Ltd. and contributors # For license information, please see license.txt -from __future__ import unicode_literals # import frappe from frappe.model.document import Document diff --git a/erpnext/quality_management/doctype/quality_meeting_agenda/test_quality_meeting_agenda.py b/erpnext/quality_management/doctype/quality_meeting_agenda/test_quality_meeting_agenda.py index 8744d275ed8..8b09f6db7fc 100644 --- a/erpnext/quality_management/doctype/quality_meeting_agenda/test_quality_meeting_agenda.py +++ b/erpnext/quality_management/doctype/quality_meeting_agenda/test_quality_meeting_agenda.py @@ -1,7 +1,5 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2019, Frappe Technologies Pvt. Ltd. and Contributors # See license.txt -from __future__ import unicode_literals # import frappe import unittest diff --git a/erpnext/quality_management/doctype/quality_meeting_minutes/quality_meeting_minutes.py b/erpnext/quality_management/doctype/quality_meeting_minutes/quality_meeting_minutes.py index e3d061b36ca..f6998df35cb 100644 --- a/erpnext/quality_management/doctype/quality_meeting_minutes/quality_meeting_minutes.py +++ b/erpnext/quality_management/doctype/quality_meeting_minutes/quality_meeting_minutes.py @@ -1,8 +1,6 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2019, Frappe Technologies Pvt. Ltd. and contributors # For license information, please see license.txt -from __future__ import unicode_literals # import frappe from frappe.model.document import Document diff --git a/erpnext/quality_management/doctype/quality_procedure/quality_procedure.py b/erpnext/quality_management/doctype/quality_procedure/quality_procedure.py index 56293c98e09..0f535ba2e11 100644 --- a/erpnext/quality_management/doctype/quality_procedure/quality_procedure.py +++ b/erpnext/quality_management/doctype/quality_procedure/quality_procedure.py @@ -1,8 +1,6 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2018, Frappe and contributors # For license information, please see license.txt -from __future__ import unicode_literals import frappe from frappe import _ diff --git a/erpnext/quality_management/doctype/quality_procedure/test_quality_procedure.py b/erpnext/quality_management/doctype/quality_procedure/test_quality_procedure.py index b064011bf6c..6130895e38d 100644 --- a/erpnext/quality_management/doctype/quality_procedure/test_quality_procedure.py +++ b/erpnext/quality_management/doctype/quality_procedure/test_quality_procedure.py @@ -1,7 +1,5 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2018, Frappe and Contributors # See license.txt -from __future__ import unicode_literals import unittest diff --git a/erpnext/quality_management/doctype/quality_procedure_process/quality_procedure_process.py b/erpnext/quality_management/doctype/quality_procedure_process/quality_procedure_process.py index e281294643d..a03c871a85d 100644 --- a/erpnext/quality_management/doctype/quality_procedure_process/quality_procedure_process.py +++ b/erpnext/quality_management/doctype/quality_procedure_process/quality_procedure_process.py @@ -1,8 +1,6 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2019, Frappe Technologies Pvt. Ltd. and contributors # For license information, please see license.txt -from __future__ import unicode_literals # import frappe from frappe.model.document import Document diff --git a/erpnext/quality_management/doctype/quality_review/quality_review.py b/erpnext/quality_management/doctype/quality_review/quality_review.py index b766623510a..b896f8dfe0c 100644 --- a/erpnext/quality_management/doctype/quality_review/quality_review.py +++ b/erpnext/quality_management/doctype/quality_review/quality_review.py @@ -1,8 +1,6 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2018, Frappe and contributors # For license information, please see license.txt -from __future__ import unicode_literals import frappe from frappe.model.document import Document diff --git a/erpnext/quality_management/doctype/quality_review/test_quality_review.py b/erpnext/quality_management/doctype/quality_review/test_quality_review.py index 2f28ddac45e..8a254dba2a5 100644 --- a/erpnext/quality_management/doctype/quality_review/test_quality_review.py +++ b/erpnext/quality_management/doctype/quality_review/test_quality_review.py @@ -1,7 +1,5 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2018, Frappe and Contributors # See license.txt -from __future__ import unicode_literals import unittest diff --git a/erpnext/quality_management/doctype/quality_review_objective/quality_review_objective.py b/erpnext/quality_management/doctype/quality_review_objective/quality_review_objective.py index 23b11e87e6a..462a97118ef 100644 --- a/erpnext/quality_management/doctype/quality_review_objective/quality_review_objective.py +++ b/erpnext/quality_management/doctype/quality_review_objective/quality_review_objective.py @@ -1,8 +1,6 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2019, Frappe Technologies Pvt. Ltd. and contributors # For license information, please see license.txt -from __future__ import unicode_literals # import frappe from frappe.model.document import Document diff --git a/erpnext/quality_management/workspace/quality/quality.json b/erpnext/quality_management/workspace/quality/quality.json index 4dc8129d890..ae284701824 100644 --- a/erpnext/quality_management/workspace/quality/quality.json +++ b/erpnext/quality_management/workspace/quality/quality.json @@ -1,20 +1,13 @@ { - "category": "", "charts": [], "content": "[{\"type\": \"header\", \"data\": {\"text\": \"Your Shortcuts\", \"level\": 4, \"col\": 12}}, {\"type\": \"shortcut\", \"data\": {\"shortcut_name\": \"Quality Goal\", \"col\": 4}}, {\"type\": \"shortcut\", \"data\": {\"shortcut_name\": \"Quality Procedure\", \"col\": 4}}, {\"type\": \"shortcut\", \"data\": {\"shortcut_name\": \"Quality Inspection\", \"col\": 4}}, {\"type\": \"shortcut\", \"data\": {\"shortcut_name\": \"Quality Review\", \"col\": 4}}, {\"type\": \"shortcut\", \"data\": {\"shortcut_name\": \"Quality Action\", \"col\": 4}}, {\"type\": \"shortcut\", \"data\": {\"shortcut_name\": \"Non Conformance\", \"col\": 4}}, {\"type\": \"spacer\", \"data\": {\"col\": 12}}, {\"type\": \"header\", \"data\": {\"text\": \"Reports & Masters\", \"level\": 4, \"col\": 12}}, {\"type\": \"card\", \"data\": {\"card_name\": \"Goal and Procedure\", \"col\": 4}}, {\"type\": \"card\", \"data\": {\"card_name\": \"Feedback\", \"col\": 4}}, {\"type\": \"card\", \"data\": {\"card_name\": \"Meeting\", \"col\": 4}}, {\"type\": \"card\", \"data\": {\"card_name\": \"Review and Action\", \"col\": 4}}]", "creation": "2020-03-02 15:49:28.632014", - "developer_mode_only": 0, - "disable_user_customization": 0, "docstatus": 0, "doctype": "Workspace", - "extends": "", - "extends_another_page": 0, "for_user": "", "hide_custom": 0, "icon": "quality", "idx": 0, - "is_default": 0, - "is_standard": 0, "label": "Quality", "links": [ { @@ -149,15 +142,12 @@ "type": "Link" } ], - "modified": "2021-08-05 12:16:01.699912", + "modified": "2021-08-05 12:16:01.699913", "modified_by": "Administrator", "module": "Quality Management", "name": "Quality", - "onboarding": "", "owner": "Administrator", "parent_page": "", - "pin_to_bottom": 0, - "pin_to_top": 0, "public": 1, "restrict_to_domain": "", "roles": [], diff --git a/erpnext/regional/__init__.py b/erpnext/regional/__init__.py index 45a689efa8b..c460286078d 100644 --- a/erpnext/regional/__init__.py +++ b/erpnext/regional/__init__.py @@ -1,7 +1,6 @@ # Copyright (c) 2018, Frappe Technologies and contributors # For license information, please see license.txt -from __future__ import unicode_literals import frappe from frappe import _ @@ -31,3 +30,4 @@ def create_transaction_log(doc, method): "document_name": doc.name, "data": data }).insert(ignore_permissions=True) + diff --git a/erpnext/regional/address_template/test_regional_address_template.py b/erpnext/regional/address_template/test_regional_address_template.py index 2880d6253f9..780db401584 100644 --- a/erpnext/regional/address_template/test_regional_address_template.py +++ b/erpnext/regional/address_template/test_regional_address_template.py @@ -1,5 +1,3 @@ -from __future__ import unicode_literals - from unittest import TestCase import frappe diff --git a/erpnext/regional/doctype/datev_settings/datev_settings.py b/erpnext/regional/doctype/datev_settings/datev_settings.py index 0d2d9eb4b47..686a93e529d 100644 --- a/erpnext/regional/doctype/datev_settings/datev_settings.py +++ b/erpnext/regional/doctype/datev_settings/datev_settings.py @@ -1,8 +1,6 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2019, Frappe Technologies Pvt. Ltd. and contributors # For license information, please see license.txt -from __future__ import unicode_literals # import frappe from frappe.model.document import Document diff --git a/erpnext/regional/doctype/datev_settings/test_datev_settings.py b/erpnext/regional/doctype/datev_settings/test_datev_settings.py index 73412f755d7..ba70eb472fe 100644 --- a/erpnext/regional/doctype/datev_settings/test_datev_settings.py +++ b/erpnext/regional/doctype/datev_settings/test_datev_settings.py @@ -1,7 +1,5 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2019, Frappe Technologies Pvt. Ltd. and Contributors # See license.txt -from __future__ import unicode_literals # import frappe import unittest diff --git a/erpnext/regional/doctype/gst_hsn_code/gst_hsn_code.py b/erpnext/regional/doctype/gst_hsn_code/gst_hsn_code.py index 0704de8387f..3b73a5c23ec 100644 --- a/erpnext/regional/doctype/gst_hsn_code/gst_hsn_code.py +++ b/erpnext/regional/doctype/gst_hsn_code/gst_hsn_code.py @@ -1,8 +1,6 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2017, Frappe Technologies Pvt. Ltd. and contributors # For license information, please see license.txt -from __future__ import unicode_literals import frappe from frappe.model.document import Document diff --git a/erpnext/regional/doctype/gst_hsn_code/test_gst_hsn_code.py b/erpnext/regional/doctype/gst_hsn_code/test_gst_hsn_code.py index 1a90e6d711c..6dbca1af1a9 100644 --- a/erpnext/regional/doctype/gst_hsn_code/test_gst_hsn_code.py +++ b/erpnext/regional/doctype/gst_hsn_code/test_gst_hsn_code.py @@ -1,7 +1,5 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2017, Frappe Technologies Pvt. Ltd. and Contributors # See license.txt -from __future__ import unicode_literals import unittest diff --git a/erpnext/regional/doctype/gst_settings/gst_settings.json b/erpnext/regional/doctype/gst_settings/gst_settings.json index 95b930c4c86..fc579d4b38c 100644 --- a/erpnext/regional/doctype/gst_settings/gst_settings.json +++ b/erpnext/regional/doctype/gst_settings/gst_settings.json @@ -6,8 +6,10 @@ "engine": "InnoDB", "field_order": [ "gst_summary", - "column_break_2", + "gst_tax_settings_section", "round_off_gst_values", + "column_break_4", + "hsn_wise_tax_breakup", "gstin_email_sent_on", "section_break_4", "gst_accounts", @@ -17,37 +19,23 @@ { "fieldname": "gst_summary", "fieldtype": "HTML", - "label": "GST Summary", - "show_days": 1, - "show_seconds": 1 - }, - { - "fieldname": "column_break_2", - "fieldtype": "Column Break", - "show_days": 1, - "show_seconds": 1 + "label": "GST Summary" }, { "fieldname": "gstin_email_sent_on", "fieldtype": "Date", "label": "GSTIN Email Sent On", - "read_only": 1, - "show_days": 1, - "show_seconds": 1 + "read_only": 1 }, { "fieldname": "section_break_4", - "fieldtype": "Section Break", - "show_days": 1, - "show_seconds": 1 + "fieldtype": "Section Break" }, { "fieldname": "gst_accounts", "fieldtype": "Table", "label": "GST Accounts", - "options": "GST Account", - "show_days": 1, - "show_seconds": 1 + "options": "GST Account" }, { "default": "250000", @@ -56,24 +44,35 @@ "fieldtype": "Data", "in_list_view": 1, "label": "B2C Limit", - "reqd": 1, - "show_days": 1, - "show_seconds": 1 + "reqd": 1 }, { "default": "0", "description": "Enabling this option will round off individual GST components in all the Invoices", "fieldname": "round_off_gst_values", "fieldtype": "Check", - "label": "Round Off GST Values", - "show_days": 1, - "show_seconds": 1 + "label": "Round Off GST Values" + }, + { + "default": "0", + "fieldname": "hsn_wise_tax_breakup", + "fieldtype": "Check", + "label": "Tax Breakup Table Based On HSN Code" + }, + { + "fieldname": "gst_tax_settings_section", + "fieldtype": "Section Break", + "label": "GST Tax Settings" + }, + { + "fieldname": "column_break_4", + "fieldtype": "Column Break" } ], "index_web_pages_for_search": 1, "issingle": 1, "links": [], - "modified": "2021-01-28 17:19:47.969260", + "modified": "2021-10-11 18:10:14.242614", "modified_by": "Administrator", "module": "Regional", "name": "GST Settings", @@ -83,4 +82,4 @@ "sort_field": "modified", "sort_order": "DESC", "track_changes": 1 - } \ No newline at end of file +} \ No newline at end of file diff --git a/erpnext/regional/doctype/gst_settings/gst_settings.py b/erpnext/regional/doctype/gst_settings/gst_settings.py index 7b27fb6c5bc..13ef3e04885 100644 --- a/erpnext/regional/doctype/gst_settings/gst_settings.py +++ b/erpnext/regional/doctype/gst_settings/gst_settings.py @@ -1,8 +1,6 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2017, Frappe Technologies Pvt. Ltd. and contributors # For license information, please see license.txt -from __future__ import unicode_literals import os diff --git a/erpnext/regional/doctype/gst_settings/test_gst_settings.py b/erpnext/regional/doctype/gst_settings/test_gst_settings.py index 836d3a88c33..5c7d2b4602f 100644 --- a/erpnext/regional/doctype/gst_settings/test_gst_settings.py +++ b/erpnext/regional/doctype/gst_settings/test_gst_settings.py @@ -1,7 +1,5 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2018, Frappe Technologies Pvt. Ltd. and Contributors # See license.txt -from __future__ import unicode_literals import unittest diff --git a/erpnext/regional/doctype/gstr_3b_report/gstr_3b_report.py b/erpnext/regional/doctype/gstr_3b_report/gstr_3b_report.py index d8ce3197395..d48cd67c384 100644 --- a/erpnext/regional/doctype/gstr_3b_report/gstr_3b_report.py +++ b/erpnext/regional/doctype/gstr_3b_report/gstr_3b_report.py @@ -1,8 +1,6 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2019, Frappe Technologies Pvt. Ltd. and contributors # For license information, please see license.txt -from __future__ import unicode_literals import json import os @@ -11,7 +9,6 @@ import frappe from frappe import _ from frappe.model.document import Document from frappe.utils import cstr, flt -from six import iteritems from erpnext.regional.india import state_numbers @@ -283,7 +280,7 @@ class GSTR3BReport(Document): if self.get('invoice_items'): # Build itemised tax for export invoices, nil and exempted where tax table is blank - for invoice, items in iteritems(self.invoice_items): + for invoice, items in self.invoice_items.items(): if invoice not in self.items_based_on_tax_rate and self.invoice_detail_map.get(invoice, {}).get('export_type') \ == "Without Payment of Tax" and self.invoice_detail_map.get(invoice, {}).get('gst_category') == "Overseas": self.items_based_on_tax_rate.setdefault(invoice, {}).setdefault(0, items.keys()) @@ -351,7 +348,7 @@ class GSTR3BReport(Document): self.report_dict['sup_details']['isup_rev']['txval'] += taxable_value def set_inter_state_supply(self, inter_state_supply): - for key, value in iteritems(inter_state_supply): + for key, value in inter_state_supply.items(): if key[0] == "Unregistered": self.report_dict["inter_sup"]["unreg_details"].append(value) diff --git a/erpnext/regional/doctype/gstr_3b_report/test_gstr_3b_report.py b/erpnext/regional/doctype/gstr_3b_report/test_gstr_3b_report.py index 115f9b88165..e12e3d7b800 100644 --- a/erpnext/regional/doctype/gstr_3b_report/test_gstr_3b_report.py +++ b/erpnext/regional/doctype/gstr_3b_report/test_gstr_3b_report.py @@ -1,7 +1,5 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2019, Frappe Technologies Pvt. Ltd. and Contributors # See license.txt -from __future__ import unicode_literals import json import unittest @@ -105,6 +103,45 @@ class TestGSTR3BReport(unittest.TestCase): gst_settings.round_off_gst_values = 1 gst_settings.save() + def test_gst_category_auto_update(self): + if not frappe.db.exists("Customer", "_Test GST Customer With GSTIN"): + customer = frappe.get_doc({ + "customer_group": "_Test Customer Group", + "customer_name": "_Test GST Customer With GSTIN", + "customer_type": "Individual", + "doctype": "Customer", + "territory": "_Test Territory" + }).insert() + + self.assertEqual(customer.gst_category, 'Unregistered') + + if not frappe.db.exists('Address', '_Test GST Category-1-Billing'): + address = frappe.get_doc({ + "address_line1": "_Test Address Line 1", + "address_title": "_Test GST Category-1", + "address_type": "Billing", + "city": "_Test City", + "state": "Test State", + "country": "India", + "doctype": "Address", + "is_primary_address": 1, + "phone": "+91 0000000000", + "gstin": "29AZWPS7135H1ZG", + "gst_state": "Karnataka", + "gst_state_number": "29" + }).insert() + + address.append("links", { + "link_doctype": "Customer", + "link_name": "_Test GST Customer With GSTIN" + }) + + address.save() + + customer.load_from_db() + self.assertEqual(customer.gst_category, 'Registered Regular') + + def make_sales_invoice(): si = create_sales_invoice(company="_Test Company GST", customer = '_Test GST Customer', diff --git a/erpnext/regional/doctype/import_supplier_invoice/import_supplier_invoice.py b/erpnext/regional/doctype/import_supplier_invoice/import_supplier_invoice.py index 76cb621f541..97b8488c2fe 100644 --- a/erpnext/regional/doctype/import_supplier_invoice/import_supplier_invoice.py +++ b/erpnext/regional/doctype/import_supplier_invoice/import_supplier_invoice.py @@ -1,7 +1,6 @@ # Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors # License: GNU General Public License v3. See license.txt -from __future__ import unicode_literals import re import zipfile diff --git a/erpnext/regional/doctype/import_supplier_invoice/test_import_supplier_invoice.py b/erpnext/regional/doctype/import_supplier_invoice/test_import_supplier_invoice.py index 4be4c3a22f9..78c07c558a5 100644 --- a/erpnext/regional/doctype/import_supplier_invoice/test_import_supplier_invoice.py +++ b/erpnext/regional/doctype/import_supplier_invoice/test_import_supplier_invoice.py @@ -1,7 +1,5 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2019, Frappe Technologies Pvt. Ltd. and Contributors # See license.txt -from __future__ import unicode_literals # import frappe import unittest diff --git a/erpnext/healthcare/doctype/exercise/__init__.py b/erpnext/regional/doctype/ksa_vat_purchase_account/__init__.py similarity index 100% rename from erpnext/healthcare/doctype/exercise/__init__.py rename to erpnext/regional/doctype/ksa_vat_purchase_account/__init__.py diff --git a/erpnext/regional/doctype/ksa_vat_purchase_account/ksa_vat_purchase_account.json b/erpnext/regional/doctype/ksa_vat_purchase_account/ksa_vat_purchase_account.json new file mode 100644 index 00000000000..89ba3e977af --- /dev/null +++ b/erpnext/regional/doctype/ksa_vat_purchase_account/ksa_vat_purchase_account.json @@ -0,0 +1,49 @@ +{ + "actions": [], + "creation": "2021-07-13 09:17:09.862163", + "doctype": "DocType", + "editable_grid": 1, + "engine": "InnoDB", + "field_order": [ + "title", + "item_tax_template", + "account" + ], + "fields": [ + { + "fieldname": "account", + "fieldtype": "Link", + "in_list_view": 1, + "label": "Account", + "options": "Account", + "reqd": 1 + }, + { + "fieldname": "title", + "fieldtype": "Data", + "in_list_view": 1, + "label": "Title", + "reqd": 1 + }, + { + "fieldname": "item_tax_template", + "fieldtype": "Link", + "in_list_view": 1, + "label": "Item Tax Template", + "options": "Item Tax Template", + "reqd": 1 + } + ], + "index_web_pages_for_search": 1, + "istable": 1, + "links": [], + "modified": "2021-08-04 06:42:38.205597", + "modified_by": "Administrator", + "module": "Regional", + "name": "KSA VAT Purchase Account", + "owner": "Administrator", + "permissions": [], + "sort_field": "modified", + "sort_order": "DESC", + "track_changes": 1 +} \ No newline at end of file diff --git a/erpnext/regional/doctype/ksa_vat_purchase_account/ksa_vat_purchase_account.py b/erpnext/regional/doctype/ksa_vat_purchase_account/ksa_vat_purchase_account.py new file mode 100644 index 00000000000..3920bc546c1 --- /dev/null +++ b/erpnext/regional/doctype/ksa_vat_purchase_account/ksa_vat_purchase_account.py @@ -0,0 +1,9 @@ +# Copyright (c) 2021, Havenir Solutions and contributors +# For license information, please see license.txt + +# import frappe +from frappe.model.document import Document + + +class KSAVATPurchaseAccount(Document): + pass diff --git a/erpnext/healthcare/doctype/exercise_difficulty_level/__init__.py b/erpnext/regional/doctype/ksa_vat_sales_account/__init__.py similarity index 100% rename from erpnext/healthcare/doctype/exercise_difficulty_level/__init__.py rename to erpnext/regional/doctype/ksa_vat_sales_account/__init__.py diff --git a/erpnext/regional/doctype/ksa_vat_sales_account/ksa_vat_sales_account.js b/erpnext/regional/doctype/ksa_vat_sales_account/ksa_vat_sales_account.js new file mode 100644 index 00000000000..72613f4064f --- /dev/null +++ b/erpnext/regional/doctype/ksa_vat_sales_account/ksa_vat_sales_account.js @@ -0,0 +1,8 @@ +// Copyright (c) 2021, Havenir Solutions and contributors +// For license information, please see license.txt + +frappe.ui.form.on('KSA VAT Sales Account', { + // refresh: function(frm) { + + // } +}); diff --git a/erpnext/regional/doctype/ksa_vat_sales_account/ksa_vat_sales_account.json b/erpnext/regional/doctype/ksa_vat_sales_account/ksa_vat_sales_account.json new file mode 100644 index 00000000000..df2747891dc --- /dev/null +++ b/erpnext/regional/doctype/ksa_vat_sales_account/ksa_vat_sales_account.json @@ -0,0 +1,49 @@ +{ + "actions": [], + "creation": "2021-07-13 08:46:33.820968", + "doctype": "DocType", + "editable_grid": 1, + "engine": "InnoDB", + "field_order": [ + "title", + "item_tax_template", + "account" + ], + "fields": [ + { + "fieldname": "account", + "fieldtype": "Link", + "in_list_view": 1, + "label": "Account", + "options": "Account", + "reqd": 1 + }, + { + "fieldname": "title", + "fieldtype": "Data", + "in_list_view": 1, + "label": "Title", + "reqd": 1 + }, + { + "fieldname": "item_tax_template", + "fieldtype": "Link", + "in_list_view": 1, + "label": "Item Tax Template", + "options": "Item Tax Template", + "reqd": 1 + } + ], + "index_web_pages_for_search": 1, + "istable": 1, + "links": [], + "modified": "2021-08-04 06:42:00.081407", + "modified_by": "Administrator", + "module": "Regional", + "name": "KSA VAT Sales Account", + "owner": "Administrator", + "permissions": [], + "sort_field": "modified", + "sort_order": "DESC", + "track_changes": 1 +} \ No newline at end of file diff --git a/erpnext/regional/doctype/ksa_vat_sales_account/ksa_vat_sales_account.py b/erpnext/regional/doctype/ksa_vat_sales_account/ksa_vat_sales_account.py new file mode 100644 index 00000000000..7c2689f530e --- /dev/null +++ b/erpnext/regional/doctype/ksa_vat_sales_account/ksa_vat_sales_account.py @@ -0,0 +1,9 @@ +# Copyright (c) 2021, Havenir Solutions and contributors +# For license information, please see license.txt + +# import frappe +from frappe.model.document import Document + + +class KSAVATSalesAccount(Document): + pass diff --git a/erpnext/regional/doctype/ksa_vat_sales_account/test_ksa_vat_sales_account.py b/erpnext/regional/doctype/ksa_vat_sales_account/test_ksa_vat_sales_account.py new file mode 100644 index 00000000000..1d6a6a793dc --- /dev/null +++ b/erpnext/regional/doctype/ksa_vat_sales_account/test_ksa_vat_sales_account.py @@ -0,0 +1,9 @@ +# Copyright (c) 2021, Havenir Solutions and Contributors +# See license.txt + +# import frappe +import unittest + + +class TestKSAVATSalesAccount(unittest.TestCase): + pass diff --git a/erpnext/healthcare/doctype/exercise_type/__init__.py b/erpnext/regional/doctype/ksa_vat_setting/__init__.py similarity index 100% rename from erpnext/healthcare/doctype/exercise_type/__init__.py rename to erpnext/regional/doctype/ksa_vat_setting/__init__.py diff --git a/erpnext/regional/doctype/ksa_vat_setting/ksa_vat_setting.js b/erpnext/regional/doctype/ksa_vat_setting/ksa_vat_setting.js new file mode 100644 index 00000000000..00b62b9adfb --- /dev/null +++ b/erpnext/regional/doctype/ksa_vat_setting/ksa_vat_setting.js @@ -0,0 +1,8 @@ +// Copyright (c) 2021, Havenir Solutions and contributors +// For license information, please see license.txt + +frappe.ui.form.on('KSA VAT Setting', { + onload: function () { + frappe.breadcrumbs.add('Accounts', 'KSA VAT Setting'); + } +}); diff --git a/erpnext/regional/doctype/ksa_vat_setting/ksa_vat_setting.json b/erpnext/regional/doctype/ksa_vat_setting/ksa_vat_setting.json new file mode 100644 index 00000000000..33619467ed0 --- /dev/null +++ b/erpnext/regional/doctype/ksa_vat_setting/ksa_vat_setting.json @@ -0,0 +1,49 @@ +{ + "actions": [], + "autoname": "field:company", + "creation": "2021-07-13 08:49:01.100356", + "doctype": "DocType", + "editable_grid": 1, + "engine": "InnoDB", + "field_order": [ + "company", + "ksa_vat_sales_accounts", + "ksa_vat_purchase_accounts" + ], + "fields": [ + { + "fieldname": "company", + "fieldtype": "Link", + "in_list_view": 1, + "label": "Company", + "options": "Company", + "reqd": 1, + "unique": 1 + }, + { + "fieldname": "ksa_vat_sales_accounts", + "fieldtype": "Table", + "label": "KSA VAT Sales Accounts", + "options": "KSA VAT Sales Account", + "reqd": 1 + }, + { + "fieldname": "ksa_vat_purchase_accounts", + "fieldtype": "Table", + "label": "KSA VAT Purchase Accounts", + "options": "KSA VAT Purchase Account", + "reqd": 1 + } + ], + "links": [], + "modified": "2021-08-26 04:29:06.499378", + "modified_by": "Administrator", + "module": "Regional", + "name": "KSA VAT Setting", + "owner": "Administrator", + "permissions": [], + "sort_field": "modified", + "sort_order": "DESC", + "title_field": "company", + "track_changes": 1 +} \ No newline at end of file diff --git a/erpnext/regional/doctype/ksa_vat_setting/ksa_vat_setting.py b/erpnext/regional/doctype/ksa_vat_setting/ksa_vat_setting.py new file mode 100644 index 00000000000..bdae1161fd7 --- /dev/null +++ b/erpnext/regional/doctype/ksa_vat_setting/ksa_vat_setting.py @@ -0,0 +1,9 @@ +# Copyright (c) 2021, Havenir Solutions and contributors +# For license information, please see license.txt + +# import frappe +from frappe.model.document import Document + + +class KSAVATSetting(Document): + pass diff --git a/erpnext/regional/doctype/ksa_vat_setting/ksa_vat_setting_list.js b/erpnext/regional/doctype/ksa_vat_setting/ksa_vat_setting_list.js new file mode 100644 index 00000000000..269cbec5fb4 --- /dev/null +++ b/erpnext/regional/doctype/ksa_vat_setting/ksa_vat_setting_list.js @@ -0,0 +1,5 @@ +frappe.listview_settings['KSA VAT Setting'] = { + onload () { + frappe.breadcrumbs.add('Accounts'); + } +} \ No newline at end of file diff --git a/erpnext/regional/doctype/ksa_vat_setting/test_ksa_vat_setting.py b/erpnext/regional/doctype/ksa_vat_setting/test_ksa_vat_setting.py new file mode 100644 index 00000000000..7207901fd43 --- /dev/null +++ b/erpnext/regional/doctype/ksa_vat_setting/test_ksa_vat_setting.py @@ -0,0 +1,9 @@ +# Copyright (c) 2021, Havenir Solutions and Contributors +# See license.txt + +# import frappe +import unittest + + +class TestKSAVATSetting(unittest.TestCase): + pass diff --git a/erpnext/regional/doctype/lower_deduction_certificate/lower_deduction_certificate.json b/erpnext/regional/doctype/lower_deduction_certificate/lower_deduction_certificate.json index f48fe6f4763..c32ab6bec24 100644 --- a/erpnext/regional/doctype/lower_deduction_certificate/lower_deduction_certificate.json +++ b/erpnext/regional/doctype/lower_deduction_certificate/lower_deduction_certificate.json @@ -7,7 +7,7 @@ "engine": "InnoDB", "field_order": [ "certificate_details_section", - "section_code", + "tax_withholding_category", "fiscal_year", "column_break_3", "certificate_no", @@ -33,13 +33,6 @@ "reqd": 1, "unique": 1 }, - { - "fieldname": "section_code", - "fieldtype": "Select", - "label": "Section Code", - "options": "192\n193\n194\n194A\n194C\n194D\n194H\n194I\n194J\n194LA\n194LBB\n194LBC\n195", - "reqd": 1 - }, { "fieldname": "section_break_3", "fieldtype": "Section Break", @@ -123,13 +116,22 @@ "label": "Fiscal Year", "options": "Fiscal Year", "reqd": 1 + }, + { + "fieldname": "tax_withholding_category", + "fieldtype": "Link", + "label": "Tax Withholding Category", + "options": "Tax Withholding Category", + "reqd": 1 } ], + "index_web_pages_for_search": 1, "links": [], - "modified": "2020-04-23 23:04:41.203721", + "modified": "2021-10-23 18:33:38.962622", "modified_by": "Administrator", "module": "Regional", "name": "Lower Deduction Certificate", + "naming_rule": "By fieldname", "owner": "Administrator", "permissions": [], "sort_field": "modified", diff --git a/erpnext/regional/doctype/lower_deduction_certificate/lower_deduction_certificate.py b/erpnext/regional/doctype/lower_deduction_certificate/lower_deduction_certificate.py index d8553f1d913..f14888189a0 100644 --- a/erpnext/regional/doctype/lower_deduction_certificate/lower_deduction_certificate.py +++ b/erpnext/regional/doctype/lower_deduction_certificate/lower_deduction_certificate.py @@ -1,8 +1,6 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2020, Frappe Technologies Pvt. Ltd. and contributors # For license information, please see license.txt -from __future__ import unicode_literals import frappe from frappe import _ @@ -15,7 +13,7 @@ from erpnext.accounts.utils import get_fiscal_year class LowerDeductionCertificate(Document): def validate(self): self.validate_dates() - self.validate_supplier_against_section_code() + self.validate_supplier_against_tax_category() def validate_dates(self): if getdate(self.valid_upto) < getdate(self.valid_from): @@ -31,12 +29,14 @@ class LowerDeductionCertificate(Document): <= fiscal_year.year_end_date): frappe.throw(_("Valid Upto date not in Fiscal Year {0}").format(frappe.bold(self.fiscal_year))) - def validate_supplier_against_section_code(self): - duplicate_certificate = frappe.db.get_value('Lower Deduction Certificate', {'supplier': self.supplier, 'section_code': self.section_code}, ['name', 'valid_from', 'valid_upto'], as_dict=True) + def validate_supplier_against_tax_category(self): + duplicate_certificate = frappe.db.get_value('Lower Deduction Certificate', + {'supplier': self.supplier, 'tax_withholding_category': self.tax_withholding_category, 'name': ("!=", self.name)}, + ['name', 'valid_from', 'valid_upto'], as_dict=True) if duplicate_certificate and self.are_dates_overlapping(duplicate_certificate): certificate_link = get_link_to_form('Lower Deduction Certificate', duplicate_certificate.name) - frappe.throw(_("There is already a valid Lower Deduction Certificate {0} for Supplier {1} against Section Code {2} for this time period.") - .format(certificate_link, frappe.bold(self.supplier), frappe.bold(self.section_code))) + frappe.throw(_("There is already a valid Lower Deduction Certificate {0} for Supplier {1} against category {2} for this time period.") + .format(certificate_link, frappe.bold(self.supplier), frappe.bold(self.tax_withholding_category))) def are_dates_overlapping(self,duplicate_certificate): valid_from = duplicate_certificate.valid_from diff --git a/erpnext/regional/doctype/lower_deduction_certificate/test_lower_deduction_certificate.py b/erpnext/regional/doctype/lower_deduction_certificate/test_lower_deduction_certificate.py index 54443c0206a..d8e78019311 100644 --- a/erpnext/regional/doctype/lower_deduction_certificate/test_lower_deduction_certificate.py +++ b/erpnext/regional/doctype/lower_deduction_certificate/test_lower_deduction_certificate.py @@ -1,7 +1,5 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2020, Frappe Technologies Pvt. Ltd. and Contributors # See license.txt -from __future__ import unicode_literals # import frappe import unittest diff --git a/erpnext/regional/doctype/tax_exemption_80g_certificate/tax_exemption_80g_certificate.py b/erpnext/regional/doctype/tax_exemption_80g_certificate/tax_exemption_80g_certificate.py index 64b2ec5646c..9a72410f67b 100644 --- a/erpnext/regional/doctype/tax_exemption_80g_certificate/tax_exemption_80g_certificate.py +++ b/erpnext/regional/doctype/tax_exemption_80g_certificate/tax_exemption_80g_certificate.py @@ -1,8 +1,6 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2021, Frappe Technologies Pvt. Ltd. and contributors # For license information, please see license.txt -from __future__ import unicode_literals import frappe from frappe import _ diff --git a/erpnext/regional/doctype/tax_exemption_80g_certificate/test_tax_exemption_80g_certificate.py b/erpnext/regional/doctype/tax_exemption_80g_certificate/test_tax_exemption_80g_certificate.py index 74e9ced3941..6fa3b85d061 100644 --- a/erpnext/regional/doctype/tax_exemption_80g_certificate/test_tax_exemption_80g_certificate.py +++ b/erpnext/regional/doctype/tax_exemption_80g_certificate/test_tax_exemption_80g_certificate.py @@ -1,7 +1,5 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2021, Frappe Technologies Pvt. Ltd. and Contributors # See license.txt -from __future__ import unicode_literals import unittest diff --git a/erpnext/regional/doctype/tax_exemption_80g_certificate_detail/tax_exemption_80g_certificate_detail.py b/erpnext/regional/doctype/tax_exemption_80g_certificate_detail/tax_exemption_80g_certificate_detail.py index 76d8912b004..bb7f07f6883 100644 --- a/erpnext/regional/doctype/tax_exemption_80g_certificate_detail/tax_exemption_80g_certificate_detail.py +++ b/erpnext/regional/doctype/tax_exemption_80g_certificate_detail/tax_exemption_80g_certificate_detail.py @@ -1,8 +1,6 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2021, Frappe Technologies Pvt. Ltd. and contributors # For license information, please see license.txt -from __future__ import unicode_literals # import frappe from frappe.model.document import Document diff --git a/erpnext/regional/doctype/uae_vat_account/uae_vat_account.py b/erpnext/regional/doctype/uae_vat_account/uae_vat_account.py index a1b27d7e3d3..f2fc34d391a 100644 --- a/erpnext/regional/doctype/uae_vat_account/uae_vat_account.py +++ b/erpnext/regional/doctype/uae_vat_account/uae_vat_account.py @@ -1,8 +1,6 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2020, Frappe Technologies Pvt. Ltd. and contributors # For license information, please see license.txt -from __future__ import unicode_literals # import frappe from frappe.model.document import Document diff --git a/erpnext/regional/doctype/uae_vat_settings/test_uae_vat_settings.py b/erpnext/regional/doctype/uae_vat_settings/test_uae_vat_settings.py index cec30e61cef..464c2e67be2 100644 --- a/erpnext/regional/doctype/uae_vat_settings/test_uae_vat_settings.py +++ b/erpnext/regional/doctype/uae_vat_settings/test_uae_vat_settings.py @@ -1,7 +1,5 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2020, Frappe Technologies Pvt. Ltd. and Contributors # See license.txt -from __future__ import unicode_literals # import frappe import unittest diff --git a/erpnext/regional/doctype/uae_vat_settings/uae_vat_settings.py b/erpnext/regional/doctype/uae_vat_settings/uae_vat_settings.py index 1bf37dd499d..1af32e4be34 100644 --- a/erpnext/regional/doctype/uae_vat_settings/uae_vat_settings.py +++ b/erpnext/regional/doctype/uae_vat_settings/uae_vat_settings.py @@ -1,8 +1,6 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2020, Frappe Technologies Pvt. Ltd. and contributors # For license information, please see license.txt -from __future__ import unicode_literals # import frappe from frappe.model.document import Document diff --git a/erpnext/regional/france/setup.py b/erpnext/regional/france/setup.py index db6419e9462..5d482030233 100644 --- a/erpnext/regional/france/setup.py +++ b/erpnext/regional/france/setup.py @@ -1,7 +1,6 @@ # Copyright (c) 2018, Frappe Technologies Pvt. Ltd. and Contributors # License: GNU General Public License v3. See license.txt -from __future__ import unicode_literals import frappe from frappe.custom.doctype.custom_field.custom_field import create_custom_fields diff --git a/erpnext/regional/france/utils.py b/erpnext/regional/france/utils.py index 63c5a1f583b..841316586dc 100644 --- a/erpnext/regional/france/utils.py +++ b/erpnext/regional/france/utils.py @@ -1,7 +1,6 @@ # Copyright (c) 2018, Frappe Technologies and contributors # For license information, please see license.txt -from __future__ import unicode_literals # don't remove this function it is used in tests diff --git a/erpnext/regional/germany/utils/datev/datev_constants.py b/erpnext/regional/germany/utils/datev/datev_constants.py index be3d7a3e542..8f2dc2dec39 100644 --- a/erpnext/regional/germany/utils/datev/datev_constants.py +++ b/erpnext/regional/germany/utils/datev/datev_constants.py @@ -1,4 +1,3 @@ -# coding: utf-8 """Constants used in datev.py.""" TRANSACTION_COLUMNS = [ diff --git a/erpnext/regional/germany/utils/datev/datev_csv.py b/erpnext/regional/germany/utils/datev/datev_csv.py index 9d1fabbada7..2d1e02eadba 100644 --- a/erpnext/regional/germany/utils/datev/datev_csv.py +++ b/erpnext/regional/germany/utils/datev/datev_csv.py @@ -1,6 +1,3 @@ -# coding: utf-8 -from __future__ import unicode_literals - import datetime import zipfile from csv import QUOTE_NONNUMERIC @@ -46,7 +43,7 @@ def get_datev_csv(data, filters, csv_class): data = result.to_csv( # Reason for str(';'): https://github.com/pandas-dev/pandas/issues/6035 - sep=str(';'), + sep=';', # European decimal seperator decimal=',', # Windows "ANSI" encoding diff --git a/erpnext/regional/india/__init__.py b/erpnext/regional/india/__init__.py index 5c4d30881d1..c703575d7de 100644 --- a/erpnext/regional/india/__init__.py +++ b/erpnext/regional/india/__init__.py @@ -1,6 +1,3 @@ -from __future__ import unicode_literals - -from six import iteritems states = [ '', @@ -83,4 +80,4 @@ state_numbers = { "West Bengal": "19", } -number_state_mapping = {v: k for k, v in iteritems(state_numbers)} +number_state_mapping = {v: k for k, v in state_numbers.items()} diff --git a/erpnext/regional/india/setup.py b/erpnext/regional/india/setup.py index 963c4075cd2..58654240285 100644 --- a/erpnext/regional/india/setup.py +++ b/erpnext/regional/india/setup.py @@ -1,7 +1,6 @@ # Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors # License: GNU General Public License v3. See license.txt -from __future__ import unicode_literals import frappe, os, json from frappe.custom.doctype.custom_field.custom_field import create_custom_fields @@ -13,7 +12,7 @@ from frappe.utils import today def setup(company=None, patch=True): # Company independent fixtures should be called only once at the first company setup - if frappe.db.count('Company', {'country': 'India'}) <=1: + if patch or frappe.db.count('Company', {'country': 'India'}) <=1: setup_company_independent_fixtures(patch=patch) if not patch: @@ -132,6 +131,10 @@ def make_property_setters(patch=False): make_property_setter('Journal Entry', 'voucher_type', 'options', '\n'.join(journal_entry_types), '') def make_custom_fields(update=True): + custom_fields = get_custom_fields() + create_custom_fields(custom_fields, update=update) + +def get_custom_fields(): hsn_sac_field = dict(fieldname='gst_hsn_code', label='HSN/SAC', fieldtype='Data', fetch_from='item_code.gst_hsn_code', insert_after='description', allow_on_submit=1, print_hide=1, fetch_if_empty=1) @@ -165,12 +168,12 @@ def make_custom_fields(update=True): dict(fieldname='gst_category', label='GST Category', fieldtype='Select', insert_after='gst_section', print_hide=1, options='\nRegistered Regular\nRegistered Composition\nUnregistered\nSEZ\nOverseas\nConsumer\nDeemed Export\nUIN Holders', - fetch_from='customer.gst_category', fetch_if_empty=1), + fetch_from='customer.gst_category', fetch_if_empty=1, length=25), dict(fieldname='export_type', label='Export Type', fieldtype='Select', insert_after='gst_category', print_hide=1, depends_on='eval:in_list(["SEZ", "Overseas", "Deemed Export"], doc.gst_category)', options='\nWith Payment of Tax\nWithout Payment of Tax', fetch_from='customer.export_type', - fetch_if_empty=1), + fetch_if_empty=1, length=25), ] delivery_note_gst_category = [ @@ -181,18 +184,18 @@ def make_custom_fields(update=True): ] invoice_gst_fields = [ - dict(fieldname='invoice_copy', label='Invoice Copy', + dict(fieldname='invoice_copy', label='Invoice Copy', length=30, fieldtype='Select', insert_after='export_type', print_hide=1, allow_on_submit=1, options='Original for Recipient\nDuplicate for Transporter\nDuplicate for Supplier\nTriplicate for Supplier'), - dict(fieldname='reverse_charge', label='Reverse Charge', + dict(fieldname='reverse_charge', label='Reverse Charge', length=2, fieldtype='Select', insert_after='invoice_copy', print_hide=1, options='Y\nN', default='N'), - dict(fieldname='ecommerce_gstin', label='E-commerce GSTIN', + dict(fieldname='ecommerce_gstin', label='E-commerce GSTIN', length=15, fieldtype='Data', insert_after='export_type', print_hide=1), dict(fieldname='gst_col_break', fieldtype='Column Break', insert_after='ecommerce_gstin'), dict(fieldname='reason_for_issuing_document', label='Reason For Issuing document', fieldtype='Select', insert_after='gst_col_break', print_hide=1, - depends_on='eval:doc.is_return==1', + depends_on='eval:doc.is_return==1', length=45, options='\n01-Sales Return\n02-Post Sale Discount\n03-Deficiency in services\n04-Correction in Invoice\n05-Change in POS\n06-Finalization of Provisional assessment\n07-Others') ] @@ -230,25 +233,25 @@ def make_custom_fields(update=True): sales_invoice_gst_fields = [ dict(fieldname='billing_address_gstin', label='Billing Address GSTIN', fieldtype='Data', insert_after='customer_address', read_only=1, - fetch_from='customer_address.gstin', print_hide=1), + fetch_from='customer_address.gstin', print_hide=1, length=15), dict(fieldname='customer_gstin', label='Customer GSTIN', fieldtype='Data', insert_after='shipping_address_name', - fetch_from='shipping_address_name.gstin', print_hide=1), + fetch_from='shipping_address_name.gstin', print_hide=1, length=15), dict(fieldname='place_of_supply', label='Place of Supply', fieldtype='Data', insert_after='customer_gstin', - print_hide=1, read_only=1), + print_hide=1, read_only=1, length=50), dict(fieldname='company_gstin', label='Company GSTIN', fieldtype='Data', insert_after='company_address', - fetch_from='company_address.gstin', print_hide=1, read_only=1), + fetch_from='company_address.gstin', print_hide=1, read_only=1, length=15), ] sales_invoice_shipping_fields = [ dict(fieldname='port_code', label='Port Code', fieldtype='Data', insert_after='reason_for_issuing_document', print_hide=1, - depends_on="eval:doc.gst_category=='Overseas' "), + depends_on="eval:doc.gst_category=='Overseas' ", length=15), dict(fieldname='shipping_bill_number', label=' Shipping Bill Number', fieldtype='Data', insert_after='port_code', print_hide=1, - depends_on="eval:doc.gst_category=='Overseas' "), + depends_on="eval:doc.gst_category=='Overseas' ", length=50), dict(fieldname='shipping_bill_date', label='Shipping Bill Date', fieldtype='Date', insert_after='shipping_bill_number', print_hide=1, depends_on="eval:doc.gst_category=='Overseas' "), @@ -354,7 +357,8 @@ def make_custom_fields(update=True): 'insert_after': 'transporter', 'fetch_from': 'transporter.gst_transporter_id', 'print_hide': 1, - 'translatable': 0 + 'translatable': 0, + 'length': 20 }, { 'fieldname': 'driver', @@ -370,7 +374,8 @@ def make_custom_fields(update=True): 'fieldtype': 'Data', 'insert_after': 'driver', 'print_hide': 1, - 'translatable': 0 + 'translatable': 0, + 'length': 30 }, { 'fieldname': 'vehicle_no', @@ -378,7 +383,8 @@ def make_custom_fields(update=True): 'fieldtype': 'Data', 'insert_after': 'lr_no', 'print_hide': 1, - 'translatable': 0 + 'translatable': 0, + 'length': 10 }, { 'fieldname': 'distance', @@ -395,7 +401,7 @@ def make_custom_fields(update=True): { 'fieldname': 'transporter_name', 'label': 'Transporter Name', - 'fieldtype': 'Data', + 'fieldtype': 'Small Text', 'insert_after': 'transporter_col_break', 'fetch_from': 'transporter.name', 'read_only': 1, @@ -409,12 +415,13 @@ def make_custom_fields(update=True): 'options': '\nRoad\nAir\nRail\nShip', 'insert_after': 'transporter_name', 'print_hide': 1, - 'translatable': 0 + 'translatable': 0, + 'length': 5 }, { 'fieldname': 'driver_name', 'label': 'Driver Name', - 'fieldtype': 'Data', + 'fieldtype': 'Small Text', 'insert_after': 'mode_of_transport', 'fetch_from': 'driver.full_name', 'print_hide': 1, @@ -437,7 +444,8 @@ def make_custom_fields(update=True): 'default': 'Regular', 'insert_after': 'lr_date', 'print_hide': 1, - 'translatable': 0 + 'translatable': 0, + 'length': 30 }, { 'fieldname': 'ewaybill', @@ -446,7 +454,8 @@ def make_custom_fields(update=True): 'depends_on': 'eval:(doc.docstatus === 1)', 'allow_on_submit': 1, 'insert_after': 'tax_id', - 'translatable': 0 + 'translatable': 0, + 'length': 20 } ] @@ -483,6 +492,7 @@ def make_custom_fields(update=True): 'Purchase Order': purchase_invoice_gst_fields, 'Purchase Receipt': purchase_invoice_gst_fields, 'Sales Invoice': sales_invoice_gst_category + invoice_gst_fields + sales_invoice_shipping_fields + sales_invoice_gst_fields + si_ewaybill_fields, + 'POS Invoice': sales_invoice_gst_fields, 'Delivery Note': sales_invoice_gst_fields + ewaybill_fields + sales_invoice_shipping_fields + delivery_note_gst_category, 'Payment Entry': payment_entry_fields, 'Journal Entry': journal_entry_fields, @@ -501,6 +511,7 @@ def make_custom_fields(update=True): 'Sales Order Item': [hsn_sac_field, nil_rated_exempt, is_non_gst], 'Delivery Note Item': [hsn_sac_field, nil_rated_exempt, is_non_gst], 'Sales Invoice Item': [hsn_sac_field, nil_rated_exempt, is_non_gst, taxable_value], + 'POS Invoice Item': [hsn_sac_field, nil_rated_exempt, is_non_gst, taxable_value], 'Purchase Order Item': [hsn_sac_field, nil_rated_exempt, is_non_gst], 'Purchase Receipt Item': [hsn_sac_field, nil_rated_exempt, is_non_gst], 'Purchase Invoice Item': [hsn_sac_field, nil_rated_exempt, is_non_gst, taxable_value], @@ -602,11 +613,17 @@ def make_custom_fields(update=True): fieldtype='Currency', insert_after='monthly_hra_exemption', read_only=1, depends_on='house_rent_payment_amount') ], 'Supplier': [ + { + 'fieldname': 'pan', + 'label': 'PAN', + 'fieldtype': 'Data', + 'insert_after': 'supplier_type' + }, { 'fieldname': 'gst_transporter_id', 'label': 'GST Transporter ID', 'fieldtype': 'Data', - 'insert_after': 'supplier_type', + 'insert_after': 'pan', 'depends_on': 'eval:doc.is_transporter' }, { @@ -628,11 +645,17 @@ def make_custom_fields(update=True): } ], 'Customer': [ + { + 'fieldname': 'pan', + 'label': 'PAN', + 'fieldtype': 'Data', + 'insert_after': 'customer_type' + }, { 'fieldname': 'gst_category', 'label': 'GST Category', 'fieldtype': 'Select', - 'insert_after': 'customer_type', + 'insert_after': 'pan', 'options': 'Registered Regular\nRegistered Composition\nUnregistered\nSEZ\nOverseas\nConsumer\nDeemed Export\nUIN Holders', 'default': 'Unregistered' }, @@ -661,9 +684,19 @@ def make_custom_fields(update=True): 'fieldtype': 'Data', 'insert_after': 'email' } + ], + 'Finance Book': [ + { + 'fieldname': 'for_income_tax', + 'label': 'For Income Tax', + 'fieldtype': 'Check', + 'insert_after': 'finance_book_name', + 'description': 'If the asset is put to use for less than 180 days, the first Depreciation Rate will be reduced by 50%.' + } ] } - create_custom_fields(custom_fields, update=update) + + return custom_fields def make_fixtures(company=None): docs = [] @@ -750,7 +783,7 @@ def set_salary_components(docs): def set_tax_withholding_category(company): accounts = [] - fiscal_year = None + fiscal_year_details = None abbr = frappe.get_value("Company", company, "abbr") tds_account = frappe.get_value("Account", 'TDS Payable - {0}'.format(abbr), 'name') @@ -758,11 +791,11 @@ def set_tax_withholding_category(company): accounts = [dict(company=company, account=tds_account)] try: - fiscal_year = get_fiscal_year(today(), verbose=0, company=company)[0] + fiscal_year_details = get_fiscal_year(today(), verbose=0) except FiscalYearError: pass - docs = get_tds_details(accounts, fiscal_year) + docs = get_tds_details(accounts, fiscal_year_details) for d in docs: if not frappe.db.exists("Tax Withholding Category", d.get("name")): @@ -777,9 +810,10 @@ def set_tax_withholding_category(company): if accounts: doc.append("accounts", accounts[0]) - if fiscal_year: + if fiscal_year_details: # if fiscal year don't match with any of the already entered data, append rate row - fy_exist = [k for k in doc.get('rates') if k.get('fiscal_year')==fiscal_year] + fy_exist = [k for k in doc.get('rates') if k.get('from_date') <= fiscal_year_details[1] \ + and k.get('to_date') >= fiscal_year_details[2]] if not fy_exist: doc.append("rates", d.get('rates')[0]) @@ -802,149 +836,149 @@ def set_tds_account(docs, company): } ]) -def get_tds_details(accounts, fiscal_year): +def get_tds_details(accounts, fiscal_year_details): # bootstrap default tax withholding sections return [ dict(name="TDS - 194C - Company", category_name="Payment to Contractors (Single / Aggregate)", doctype="Tax Withholding Category", accounts=accounts, - rates=[{"fiscal_year": fiscal_year, "tax_withholding_rate": 2, - "single_threshold": 30000, "cumulative_threshold": 100000}]), + rates=[{"from_date": fiscal_year_details[1], "to_date": fiscal_year_details[2], + "tax_withholding_rate": 2, "single_threshold": 30000, "cumulative_threshold": 100000}]), dict(name="TDS - 194C - Individual", category_name="Payment to Contractors (Single / Aggregate)", doctype="Tax Withholding Category", accounts=accounts, - rates=[{"fiscal_year": fiscal_year, "tax_withholding_rate": 1, - "single_threshold": 30000, "cumulative_threshold": 100000}]), + rates=[{"from_date": fiscal_year_details[1], "to_date": fiscal_year_details[2], + "tax_withholding_rate": 1, "single_threshold": 30000, "cumulative_threshold": 100000}]), dict(name="TDS - 194C - No PAN / Invalid PAN", category_name="Payment to Contractors (Single / Aggregate)", doctype="Tax Withholding Category", accounts=accounts, - rates=[{"fiscal_year": fiscal_year, "tax_withholding_rate": 20, - "single_threshold": 30000, "cumulative_threshold": 100000}]), + rates=[{"from_date": fiscal_year_details[1], "to_date": fiscal_year_details[2], + "tax_withholding_rate": 20, "single_threshold": 30000, "cumulative_threshold": 100000}]), dict(name="TDS - 194D - Company", category_name="Insurance Commission", doctype="Tax Withholding Category", accounts=accounts, - rates=[{"fiscal_year": fiscal_year, "tax_withholding_rate": 5, - "single_threshold": 15000, "cumulative_threshold": 0}]), + rates=[{"from_date": fiscal_year_details[1], "to_date": fiscal_year_details[2], + "tax_withholding_rate": 5, "single_threshold": 15000, "cumulative_threshold": 0}]), dict(name="TDS - 194D - Company Assessee", category_name="Insurance Commission", doctype="Tax Withholding Category", accounts=accounts, - rates=[{"fiscal_year": fiscal_year, "tax_withholding_rate": 10, - "single_threshold": 15000, "cumulative_threshold": 0}]), + rates=[{"from_date": fiscal_year_details[1], "to_date": fiscal_year_details[2], + "tax_withholding_rate": 10, "single_threshold": 15000, "cumulative_threshold": 0}]), dict(name="TDS - 194D - Individual", category_name="Insurance Commission", doctype="Tax Withholding Category", accounts=accounts, - rates=[{"fiscal_year": fiscal_year, "tax_withholding_rate": 5, - "single_threshold": 15000, "cumulative_threshold": 0}]), + rates=[{"from_date": fiscal_year_details[1], "to_date": fiscal_year_details[2], + "tax_withholding_rate": 5, "single_threshold": 15000, "cumulative_threshold": 0}]), dict(name="TDS - 194D - No PAN / Invalid PAN", category_name="Insurance Commission", doctype="Tax Withholding Category", accounts=accounts, - rates=[{"fiscal_year": fiscal_year, "tax_withholding_rate": 20, - "single_threshold": 15000, "cumulative_threshold": 0}]), + rates=[{"from_date": fiscal_year_details[1], "to_date": fiscal_year_details[2], + "tax_withholding_rate": 20, "single_threshold": 15000, "cumulative_threshold": 0}]), dict(name="TDS - 194DA - Company", category_name="Non-exempt payments made under a life insurance policy", doctype="Tax Withholding Category", accounts=accounts, - rates=[{"fiscal_year": fiscal_year, "tax_withholding_rate": 1, - "single_threshold": 100000, "cumulative_threshold": 0}]), + rates=[{"from_date": fiscal_year_details[1], "to_date": fiscal_year_details[2], + "tax_withholding_rate": 1, "single_threshold": 100000, "cumulative_threshold": 0}]), dict(name="TDS - 194DA - Individual", category_name="Non-exempt payments made under a life insurance policy", doctype="Tax Withholding Category", accounts=accounts, - rates=[{"fiscal_year": fiscal_year, "tax_withholding_rate": 1, - "single_threshold": 100000, "cumulative_threshold": 0}]), + rates=[{"from_date": fiscal_year_details[1], "to_date": fiscal_year_details[2], + "tax_withholding_rate": 1, "single_threshold": 100000, "cumulative_threshold": 0}]), dict(name="TDS - 194DA - No PAN / Invalid PAN", category_name="Non-exempt payments made under a life insurance policy", doctype="Tax Withholding Category", accounts=accounts, - rates=[{"fiscal_year": fiscal_year, "tax_withholding_rate": 20, - "single_threshold": 100000, "cumulative_threshold": 0}]), + rates=[{"from_date": fiscal_year_details[1], "to_date": fiscal_year_details[2], + "tax_withholding_rate": 20, "single_threshold": 100000, "cumulative_threshold": 0}]), dict(name="TDS - 194H - Company", category_name="Commission / Brokerage", doctype="Tax Withholding Category", accounts=accounts, - rates=[{"fiscal_year": fiscal_year, "tax_withholding_rate": 5, - "single_threshold": 15000, "cumulative_threshold": 0}]), + rates=[{"from_date": fiscal_year_details[1], "to_date": fiscal_year_details[2], + "tax_withholding_rate": 5, "single_threshold": 15000, "cumulative_threshold": 0}]), dict(name="TDS - 194H - Individual", category_name="Commission / Brokerage", doctype="Tax Withholding Category", accounts=accounts, - rates=[{"fiscal_year": fiscal_year, "tax_withholding_rate": 5, - "single_threshold": 15000, "cumulative_threshold": 0}]), + rates=[{"from_date": fiscal_year_details[1], "to_date": fiscal_year_details[2], + "tax_withholding_rate": 5, "single_threshold": 15000, "cumulative_threshold": 0}]), dict(name="TDS - 194H - No PAN / Invalid PAN", category_name="Commission / Brokerage", doctype="Tax Withholding Category", accounts=accounts, - rates=[{"fiscal_year": fiscal_year, "tax_withholding_rate": 20, - "single_threshold": 15000, "cumulative_threshold": 0}]), + rates=[{"from_date": fiscal_year_details[1], "to_date": fiscal_year_details[2], + "tax_withholding_rate": 20, "single_threshold": 15000, "cumulative_threshold": 0}]), dict(name="TDS - 194I - Rent - Company", category_name="Rent", doctype="Tax Withholding Category", accounts=accounts, - rates=[{"fiscal_year": fiscal_year, "tax_withholding_rate": 10, - "single_threshold": 180000, "cumulative_threshold": 0}]), + rates=[{"from_date": fiscal_year_details[1], "to_date": fiscal_year_details[2], + "tax_withholding_rate": 10, "single_threshold": 180000, "cumulative_threshold": 0}]), dict(name="TDS - 194I - Rent - Individual", category_name="Rent", doctype="Tax Withholding Category", accounts=accounts, - rates=[{"fiscal_year": fiscal_year, "tax_withholding_rate": 10, - "single_threshold": 180000, "cumulative_threshold": 0}]), + rates=[{"from_date": fiscal_year_details[1], "to_date": fiscal_year_details[2], + "tax_withholding_rate": 10, "single_threshold": 180000, "cumulative_threshold": 0}]), dict(name="TDS - 194I - Rent - No PAN / Invalid PAN", category_name="Rent", doctype="Tax Withholding Category", accounts=accounts, - rates=[{"fiscal_year": fiscal_year, "tax_withholding_rate": 20, - "single_threshold": 180000, "cumulative_threshold": 0}]), + rates=[{"from_date": fiscal_year_details[1], "to_date": fiscal_year_details[2], + "tax_withholding_rate": 20, "single_threshold": 180000, "cumulative_threshold": 0}]), dict(name="TDS - 194I - Rent/Machinery - Company", category_name="Rent-Plant / Machinery", doctype="Tax Withholding Category", accounts=accounts, - rates=[{"fiscal_year": fiscal_year, "tax_withholding_rate": 2, - "single_threshold": 180000, "cumulative_threshold": 0}]), + rates=[{"from_date": fiscal_year_details[1], "to_date": fiscal_year_details[2], + "tax_withholding_rate": 2, "single_threshold": 180000, "cumulative_threshold": 0}]), dict(name="TDS - 194I - Rent/Machinery - Individual", category_name="Rent-Plant / Machinery", doctype="Tax Withholding Category", accounts=accounts, - rates=[{"fiscal_year": fiscal_year, "tax_withholding_rate": 2, - "single_threshold": 180000, "cumulative_threshold": 0}]), + rates=[{"from_date": fiscal_year_details[1], "to_date": fiscal_year_details[2], + "tax_withholding_rate": 2, "single_threshold": 180000, "cumulative_threshold": 0}]), dict(name="TDS - 194I - Rent/Machinery - No PAN / Invalid PAN", category_name="Rent-Plant / Machinery", doctype="Tax Withholding Category", accounts=accounts, - rates=[{"fiscal_year": fiscal_year, "tax_withholding_rate": 20, - "single_threshold": 180000, "cumulative_threshold": 0}]), + rates=[{"from_date": fiscal_year_details[1], "to_date": fiscal_year_details[2], + "tax_withholding_rate": 20, "single_threshold": 180000, "cumulative_threshold": 0}]), dict(name="TDS - 194J - Professional Fees - Company", category_name="Professional Fees", doctype="Tax Withholding Category", accounts=accounts, - rates=[{"fiscal_year": fiscal_year, "tax_withholding_rate": 10, - "single_threshold": 30000, "cumulative_threshold": 0}]), + rates=[{"from_date": fiscal_year_details[1], "to_date": fiscal_year_details[2], + "tax_withholding_rate": 10, "single_threshold": 30000, "cumulative_threshold": 0}]), dict(name="TDS - 194J - Professional Fees - Individual", category_name="Professional Fees", doctype="Tax Withholding Category", accounts=accounts, - rates=[{"fiscal_year": fiscal_year, "tax_withholding_rate": 10, - "single_threshold": 30000, "cumulative_threshold": 0}]), + rates=[{"from_date": fiscal_year_details[1], "to_date": fiscal_year_details[2], + "tax_withholding_rate": 10, "single_threshold": 30000, "cumulative_threshold": 0}]), dict(name="TDS - 194J - Professional Fees - No PAN / Invalid PAN", category_name="Professional Fees", doctype="Tax Withholding Category", accounts=accounts, - rates=[{"fiscal_year": fiscal_year, "tax_withholding_rate": 20, - "single_threshold": 30000, "cumulative_threshold": 0}]), + rates=[{"from_date": fiscal_year_details[1], "to_date": fiscal_year_details[2], + "tax_withholding_rate": 20, "single_threshold": 30000, "cumulative_threshold": 0}]), dict(name="TDS - 194J - Director Fees - Company", category_name="Director Fees", doctype="Tax Withholding Category", accounts=accounts, - rates=[{"fiscal_year": fiscal_year, "tax_withholding_rate": 10, - "single_threshold": 0, "cumulative_threshold": 0}]), + rates=[{"from_date": fiscal_year_details[1], "to_date": fiscal_year_details[2], + "tax_withholding_rate": 10, "single_threshold": 0, "cumulative_threshold": 0}]), dict(name="TDS - 194J - Director Fees - Individual", category_name="Director Fees", doctype="Tax Withholding Category", accounts=accounts, - rates=[{"fiscal_year": fiscal_year, "tax_withholding_rate": 10, - "single_threshold": 0, "cumulative_threshold": 0}]), + rates=[{"from_date": fiscal_year_details[1], "to_date": fiscal_year_details[2], + "tax_withholding_rate": 10, "single_threshold": 0, "cumulative_threshold": 0}]), dict(name="TDS - 194J - Director Fees - No PAN / Invalid PAN", category_name="Director Fees", doctype="Tax Withholding Category", accounts=accounts, - rates=[{"fiscal_year": fiscal_year, "tax_withholding_rate": 20, - "single_threshold": 0, "cumulative_threshold": 0}]), + rates=[{"from_date": fiscal_year_details[1], "to_date": fiscal_year_details[2], + "tax_withholding_rate": 20, "single_threshold": 0, "cumulative_threshold": 0}]), dict(name="TDS - 194 - Dividends - Company", category_name="Dividends", doctype="Tax Withholding Category", accounts=accounts, - rates=[{"fiscal_year": fiscal_year, "tax_withholding_rate": 10, - "single_threshold": 2500, "cumulative_threshold": 0}]), + rates=[{"from_date": fiscal_year_details[1], "to_date": fiscal_year_details[2], + "tax_withholding_rate": 10, "single_threshold": 2500, "cumulative_threshold": 0}]), dict(name="TDS - 194 - Dividends - Individual", category_name="Dividends", doctype="Tax Withholding Category", accounts=accounts, - rates=[{"fiscal_year": fiscal_year, "tax_withholding_rate": 10, - "single_threshold": 2500, "cumulative_threshold": 0}]), + rates=[{"from_date": fiscal_year_details[1], "to_date": fiscal_year_details[2], + "tax_withholding_rate": 10, "single_threshold": 2500, "cumulative_threshold": 0}]), dict(name="TDS - 194 - Dividends - No PAN / Invalid PAN", category_name="Dividends", doctype="Tax Withholding Category", accounts=accounts, - rates=[{"fiscal_year": fiscal_year, "tax_withholding_rate": 20, - "single_threshold": 2500, "cumulative_threshold": 0}]) + rates=[{"from_date": fiscal_year_details[1], "to_date": fiscal_year_details[2], + "tax_withholding_rate": 20, "single_threshold": 2500, "cumulative_threshold": 0}]) ] def create_gratuity_rule(): diff --git a/erpnext/regional/india/test_utils.py b/erpnext/regional/india/test_utils.py index 2c77c8d8aa8..c95a0b3cc65 100644 --- a/erpnext/regional/india/test_utils.py +++ b/erpnext/regional/india/test_utils.py @@ -1,5 +1,3 @@ -from __future__ import unicode_literals - import unittest from unittest.mock import patch diff --git a/erpnext/regional/india/utils.py b/erpnext/regional/india/utils.py index bf06d4a497d..4bd91951916 100644 --- a/erpnext/regional/india/utils.py +++ b/erpnext/regional/india/utils.py @@ -1,5 +1,3 @@ -from __future__ import unicode_literals - import json import re @@ -7,7 +5,6 @@ import frappe from frappe import _ from frappe.model.utils import get_fetch_values from frappe.utils import cint, cstr, date_diff, flt, getdate, nowdate -from six import string_types from erpnext.controllers.accounts_controller import get_taxes_and_charges from erpnext.controllers.taxes_and_totals import get_itemised_tax, get_itemised_taxable_amount @@ -29,12 +26,13 @@ def validate_gstin_for_india(doc, method): gst_category = [] - if len(doc.links): - link_doctype = doc.links[0].get("link_doctype") - link_name = doc.links[0].get("link_name") + if hasattr(doc, 'gst_category'): + if len(doc.links): + link_doctype = doc.links[0].get("link_doctype") + link_name = doc.links[0].get("link_name") - if link_doctype in ["Customer", "Supplier"]: - gst_category = frappe.db.get_value(link_doctype, {'name': link_name}, ['gst_category']) + if link_doctype in ["Customer", "Supplier"]: + gst_category = frappe.db.get_value(link_doctype, {'name': link_name}, ['gst_category']) doc.gstin = doc.gstin.upper().strip() if not doc.gstin or doc.gstin == 'NA': @@ -62,7 +60,7 @@ def validate_gstin_for_india(doc, method): .format(doc.gst_state_number), title=_("Invalid GSTIN")) def validate_pan_for_india(doc, method): - if doc.get('country') != 'India' or not doc.pan: + if doc.get('country') != 'India' or not doc.get('pan'): return if not PAN_NUMBER_FORMAT.match(doc.pan): @@ -78,10 +76,9 @@ def validate_tax_category(doc, method): def update_gst_category(doc, method): for link in doc.links: if link.link_doctype in ['Customer', 'Supplier']: - if doc.get('gstin'): - frappe.db.sql(""" - UPDATE `tab{0}` SET gst_category = %s WHERE name = %s AND gst_category = 'Unregistered' - """.format(link.link_doctype), ("Registered Regular", link.link_name)) #nosec + meta = frappe.get_meta(link.link_doctype) + if doc.get('gstin') and meta.has_field('gst_category'): + frappe.db.set_value(link.link_doctype, {'name': link.link_name, 'gst_category': 'Unregistered'}, 'gst_category', 'Registered Regular') def set_gst_state_and_state_number(doc): if not doc.gst_state: @@ -112,12 +109,13 @@ def validate_gstin_check_digit(gstin, label='GSTIN'): frappe.throw(_("""Invalid {0}! The check digit validation has failed. Please ensure you've typed the {0} correctly.""").format(label)) def get_itemised_tax_breakup_header(item_doctype, tax_accounts): - if frappe.get_meta(item_doctype).has_field('gst_hsn_code'): + hsn_wise_in_gst_settings = frappe.db.get_single_value('GST Settings','hsn_wise_tax_breakup') + if frappe.get_meta(item_doctype).has_field('gst_hsn_code') and hsn_wise_in_gst_settings: return [_("HSN/SAC"), _("Taxable Amount")] + tax_accounts else: return [_("Item"), _("Taxable Amount")] + tax_accounts -def get_itemised_tax_breakup_data(doc, account_wise=False): +def get_itemised_tax_breakup_data(doc, account_wise=False, hsn_wise=False): itemised_tax = get_itemised_tax(doc.taxes, with_tax_account=account_wise) itemised_taxable_amount = get_itemised_taxable_amount(doc.items) @@ -125,28 +123,32 @@ def get_itemised_tax_breakup_data(doc, account_wise=False): if not frappe.get_meta(doc.doctype + " Item").has_field('gst_hsn_code'): return itemised_tax, itemised_taxable_amount - item_hsn_map = frappe._dict() - for d in doc.items: - item_hsn_map.setdefault(d.item_code or d.item_name, d.get("gst_hsn_code")) + hsn_wise_in_gst_settings = frappe.db.get_single_value('GST Settings','hsn_wise_tax_breakup') + + tax_breakup_hsn_wise = hsn_wise or hsn_wise_in_gst_settings + if tax_breakup_hsn_wise: + item_hsn_map = frappe._dict() + for d in doc.items: + item_hsn_map.setdefault(d.item_code or d.item_name, d.get("gst_hsn_code")) hsn_tax = {} for item, taxes in itemised_tax.items(): - hsn_code = item_hsn_map.get(item) - hsn_tax.setdefault(hsn_code, frappe._dict()) + item_or_hsn = item if not tax_breakup_hsn_wise else item_hsn_map.get(item) + hsn_tax.setdefault(item_or_hsn, frappe._dict()) for tax_desc, tax_detail in taxes.items(): key = tax_desc if account_wise: key = tax_detail.get('tax_account') - hsn_tax[hsn_code].setdefault(key, {"tax_rate": 0, "tax_amount": 0}) - hsn_tax[hsn_code][key]["tax_rate"] = tax_detail.get("tax_rate") - hsn_tax[hsn_code][key]["tax_amount"] += tax_detail.get("tax_amount") + hsn_tax[item_or_hsn].setdefault(key, {"tax_rate": 0, "tax_amount": 0}) + hsn_tax[item_or_hsn][key]["tax_rate"] = tax_detail.get("tax_rate") + hsn_tax[item_or_hsn][key]["tax_amount"] += tax_detail.get("tax_amount") # set taxable amount hsn_taxable_amount = frappe._dict() for item in itemised_taxable_amount: - hsn_code = item_hsn_map.get(item) - hsn_taxable_amount.setdefault(hsn_code, 0) - hsn_taxable_amount[hsn_code] += itemised_taxable_amount.get(item) + item_or_hsn = item if not tax_breakup_hsn_wise else item_hsn_map.get(item) + hsn_taxable_amount.setdefault(item_or_hsn, 0) + hsn_taxable_amount[item_or_hsn] += itemised_taxable_amount.get(item) return hsn_tax, hsn_taxable_amount @@ -189,7 +191,7 @@ def get_place_of_supply(party_details, doctype): @frappe.whitelist() def get_regional_address_details(party_details, doctype, company): - if isinstance(party_details, string_types): + if isinstance(party_details, str): party_details = json.loads(party_details) party_details = frappe._dict(party_details) @@ -251,6 +253,9 @@ def is_internal_transfer(party_details, doctype): elif doctype in ("Purchase Invoice", "Purchase Order", "Purchase Receipt"): destination_gstin = party_details.supplier_gstin + if not destination_gstin or party_details.gstin: + return False + if party_details.gstin == destination_gstin: return True else: @@ -438,9 +443,9 @@ def get_ewb_data(dt, dn): data = get_address_details(data, doc, company_address, billing_address, dispatch_address) data.itemList = [] - data.totalValue = doc.total + data.totalValue = doc.net_total - data = get_item_list(data, doc) + data = get_item_list(data, doc, hsn_wise=True) disable_rounded = frappe.db.get_single_value('Global Defaults', 'disable_rounded_total') data.totInvValue = doc.grand_total if disable_rounded else doc.rounded_total @@ -551,7 +556,7 @@ def get_address_details(data, doc, company_address, billing_address, dispatch_ad return data -def get_item_list(data, doc): +def get_item_list(data, doc, hsn_wise=False): for attr in ['cgstValue', 'sgstValue', 'igstValue', 'cessValue', 'OthValue']: data[attr] = 0 @@ -563,7 +568,7 @@ def get_item_list(data, doc): 'cess_account': ['cessRate', 'cessValue'] } item_data_attrs = ['sgstRate', 'cgstRate', 'igstRate', 'cessRate', 'cessNonAdvol'] - hsn_wise_charges, hsn_taxable_amount = get_itemised_tax_breakup_data(doc, account_wise=True) + hsn_wise_charges, hsn_taxable_amount = get_itemised_tax_breakup_data(doc, account_wise=True, hsn_wise=hsn_wise) for hsn_code, taxable_amount in hsn_taxable_amount.items(): item_data = frappe._dict() if not hsn_code: @@ -783,7 +788,7 @@ def get_regional_round_off_accounts(company, account_list): if country != 'India': return - if isinstance(account_list, string_types): + if isinstance(account_list, str): account_list = json.loads(account_list) if not frappe.db.get_single_value('GST Settings', 'round_off_gst_values'): @@ -847,7 +852,7 @@ def get_depreciation_amount(asset, depreciable_value, row): if row.depreciation_method in ("Straight Line", "Manual"): # if the Depreciation Schedule is being prepared for the first time if not asset.flags.increase_in_asset_life: - depreciation_amount = (flt(row.value_after_depreciation) - + depreciation_amount = (flt(asset.gross_purchase_amount) - flt(asset.opening_accumulated_depreciation) - flt(row.expected_value_after_useful_life)) / depreciation_left # if the Depreciation Schedule is being modified after Asset Repair @@ -859,12 +864,13 @@ def get_depreciation_amount(asset, depreciable_value, row): rate_of_depreciation = row.rate_of_depreciation # if its the first depreciation if depreciable_value == asset.gross_purchase_amount: - # as per IT act, if the asset is purchased in the 2nd half of fiscal year, then rate is divided by 2 - diff = date_diff(row.depreciation_start_date, asset.available_for_use_date) - if diff <= 180: - rate_of_depreciation = rate_of_depreciation / 2 - frappe.msgprint( - _('As per IT Act, the rate of depreciation for the first depreciation entry is reduced by 50%.')) + if row.finance_book and frappe.db.get_value('Finance Book', row.finance_book, 'for_income_tax'): + # as per IT act, if the asset is purchased in the 2nd half of fiscal year, then rate is divided by 2 + diff = date_diff(row.depreciation_start_date, asset.available_for_use_date) + if diff <= 180: + rate_of_depreciation = rate_of_depreciation / 2 + frappe.msgprint( + _('As per IT Act, the rate of depreciation for the first depreciation entry is reduced by 50%.')) depreciation_amount = flt(depreciable_value * (flt(rate_of_depreciation) / 100)) diff --git a/erpnext/regional/italy/__init__.py b/erpnext/regional/italy/__init__.py index 4932f660ca5..eb20f65afb4 100644 --- a/erpnext/regional/italy/__init__.py +++ b/erpnext/regional/italy/__init__.py @@ -1,5 +1,3 @@ -# coding=utf-8 - fiscal_regimes = [ "RF01-Ordinario", "RF02-Contribuenti minimi (art.1, c.96-117, L. 244/07)", diff --git a/erpnext/regional/italy/setup.py b/erpnext/regional/italy/setup.py index 7db2f6b0f8d..531f10d3f99 100644 --- a/erpnext/regional/italy/setup.py +++ b/erpnext/regional/italy/setup.py @@ -2,7 +2,6 @@ # License: GNU General Public License v3. See license.txt # coding=utf-8 -from __future__ import unicode_literals import frappe from frappe import _ diff --git a/erpnext/regional/italy/utils.py b/erpnext/regional/italy/utils.py index d6c7f1dbfa9..c82557b9de0 100644 --- a/erpnext/regional/italy/utils.py +++ b/erpnext/regional/italy/utils.py @@ -1,5 +1,3 @@ -from __future__ import unicode_literals - import io import json @@ -7,7 +5,6 @@ import frappe from frappe import _ from frappe.utils import cstr, flt from frappe.utils.file_manager import remove_file -from six import string_types from erpnext.controllers.taxes_and_totals import get_itemised_tax from erpnext.regional.italy import state_codes @@ -168,7 +165,7 @@ def get_invoice_summary(items, taxes): if tax.rate == 0: for item in items: item_tax_rate = item.item_tax_rate - if isinstance(item.item_tax_rate, string_types): + if isinstance(item.item_tax_rate, str): item_tax_rate = json.loads(item.item_tax_rate) if item_tax_rate and tax.account_head in item_tax_rate: diff --git a/erpnext/healthcare/doctype/exercise_type_step/__init__.py b/erpnext/regional/print_format/ksa_vat_invoice/__init__.py similarity index 100% rename from erpnext/healthcare/doctype/exercise_type_step/__init__.py rename to erpnext/regional/print_format/ksa_vat_invoice/__init__.py diff --git a/erpnext/regional/print_format/ksa_vat_invoice/ksa_vat_invoice.json b/erpnext/regional/print_format/ksa_vat_invoice/ksa_vat_invoice.json new file mode 100644 index 00000000000..681f72fd309 --- /dev/null +++ b/erpnext/regional/print_format/ksa_vat_invoice/ksa_vat_invoice.json @@ -0,0 +1,32 @@ +{ + "absolute_value": 0, + "align_labels_right": 0, + "creation": "2021-10-29 22:46:26.039023", + "css": ".qr-code{\n float:right;\n}\n\n.invoice-heading {\n margin: 0;\n}\n\n.ksa-invoice-table {\n border: 1px solid #888a8e;\n border-collapse: collapse;\n width: 100%;\n margin: 20px 0;\n font-size: 16px;\n}\n\n.ksa-invoice-table.two-columns td:nth-child(2) {\n direction: rtl;\n}\n\n.ksa-invoice-table th {\n border: 1px solid #888a8e;\n max-width: 50%;\n padding: 8px;\n}\n\n.ksa-invoice-table td {\n padding: 5px;\n border: 1px solid #888a8e;\n max-width: 50%;\n}\n\n.ksa-invoice-table thead,\n.ksa-invoice-table tfoot {\n text-transform: uppercase;\n}\n\n.qr-rtl {\n direction: rtl;\n}\n\n.qr-flex{\n display: flex;\n justify-content: space-between;\n}", + "custom_format": 1, + "default_print_language": "en", + "disabled": 0, + "doc_type": "Sales Invoice", + "docstatus": 0, + "doctype": "Print Format", + "font_size": 14, + "html": "
    \n
    \n
    \n

    TAX INVOICE

    \n

    \u0641\u0627\u062a\u0648\u0631\u0629 \u0636\u0631\u064a\u0628\u064a\u0629

    \n
    \n \n \n
    \n {% set company = frappe.get_doc(\"Company\", doc.company)%}\n {% if (doc.company_address) %}\n {% set supplier_address_doc = frappe.get_doc('Address', doc.company_address) %}\n {% endif %}\n \n {% if(doc.customer_address) %}\n {% set customer_address = frappe.get_doc('Address', doc.customer_address ) %}\n {% endif %}\n \n {% if(doc.shipping_address_name) %}\n {% set customer_shipping_address = frappe.get_doc('Address', doc.shipping_address_name ) %}\n {% endif %} \n \n \n \n \n \n \n \n \n\n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n\t\t{% if (company.tax_id) %}\n \n \n \n \n \n \n \n \n {% endif %}\n \n \n \n \n \n \n {% if(supplier_address_doc) %}\n \n \n \n \n \n \n \n \n \n \n \n \n {% endif %}\n \n \n \n \n \n \n\t\t{% set customer_tax_id = frappe.db.get_value('Customer', doc.customer, 'tax_id') %}\n\t\t{% if customer_tax_id %}\n \n \n \n \n \n \n \n \n {% endif %}\n \n \n \n \n \n {% if(customer_address) %}\n \n \n \n \n {% endif %}\n \n {% if(customer_shipping_address) %}\n \n \n \n \n \n \n \n \n \n {% endif %}\n \n\t\t{% if(doc.po_no) %}\n \n \n \n \n \n \n \n \n \n {% endif %}\n \n \n \n \n \n \n
    {{ company.name }}{{ company.company_name_in_arabic }}
    Invoice#: {{doc.name}}\u0631\u0642\u0645 \u0627\u0644\u0641\u0627\u062a\u0648\u0631\u0629: {{doc.name}}
    Invoice Date: {{doc.posting_date}}\u062a\u0627\u0631\u064a\u062e \u0627\u0644\u0641\u0627\u062a\u0648\u0631\u0629: {{doc.posting_date}}
    Date of Supply:{{doc.posting_date}}\u062a\u0627\u0631\u064a\u062e \u0627\u0644\u062a\u0648\u0631\u064a\u062f: {{doc.posting_date}}
    Supplier:\u0627\u0644\u0645\u0648\u0631\u062f:
    Supplier Tax Identification Number:\u0631\u0642\u0645 \u0627\u0644\u062a\u0639\u0631\u064a\u0641 \u0627\u0644\u0636\u0631\u064a\u0628\u064a \u0644\u0644\u0645\u0648\u0631\u062f:
    {{ company.tax_id }}{{ company.tax_id }}
    {{ company.name }}{{ company.company_name_in_arabic }}
    {{ supplier_address_doc.address_line1}} {{ supplier_address_doc.address_in_arabic}}
    Phone: {{ supplier_address_doc.phone }}\u0647\u0627\u062a\u0641: {{ supplier_address_doc.phone }}
    Email: {{ supplier_address_doc.email_id }}\u0628\u0631\u064a\u062f \u0627\u0644\u0643\u062a\u0631\u0648\u0646\u064a: {{ supplier_address_doc.email_id }}
    CUSTOMER:\u0639\u0645\u064a\u0644:
    Customer Tax Identification Number:\u0631\u0642\u0645 \u0627\u0644\u062a\u0639\u0631\u064a\u0641 \u0627\u0644\u0636\u0631\u064a\u0628\u064a \u0644\u0644\u0639\u0645\u064a\u0644:
    {{ customer_tax_id }}{{ customer_tax_id }}
    {{ doc.customer }} {{ doc.customer_name_in_arabic }}
    {{ customer_address.address_line1}} {{ customer_address.address_in_arabic}}
    SHIPPING ADDRESS:\u0639\u0646\u0648\u0627\u0646 \u0627\u0644\u0634\u062d\u0646:
    {{ customer_shipping_address.address_line1}} {{ customer_shipping_address.address_in_arabic}}
    OTHER INFORMATION\u0645\u0639\u0644\u0648\u0645\u0627\u062a \u0623\u062e\u0631\u0649
    Purchase Order Number: {{ doc.po_no }}\u0631\u0642\u0645 \u0623\u0645\u0631 \u0627\u0644\u0634\u0631\u0627\u0621: {{ doc.po_no }}
    Payment Due Date: {{ doc.due_date}} \u062a\u0627\u0631\u064a\u062e \u0627\u0633\u062a\u062d\u0642\u0627\u0642 \u0627\u0644\u062f\u0641\u0639: {{ doc.due_date}}
    \n\n \n {% set col = namespace(one = 2, two = 1) %}\n {% set length = doc.taxes | length %}\n {% set length = length / 2 | round %}\n {% set col.one = col.one + length %}\n {% set col.two = col.two + length %}\n \n {%- if(doc.taxes | length % 2 > 0 ) -%}\n {% set col.two = col.two + 1 %}\n {% endif %}\n \n \n {% set total = namespace(amount = 0) %}\n \n \n \n \n \n \n \n \n {% for row in doc.taxes %}\n \n {% endfor %}\n \n \n \n \n \n {%- for item in doc.items -%}\n {% set total.amount = item.amount %}\n \n \n \n \n \n {% for row in doc.taxes %}\n {% set data_object = json.loads(row.item_wise_tax_detail) %}\n {% set tax_amount = frappe.utils.flt(data_object[item.item_code][1]/doc.conversion_rate, row.precision('tax_amount')) %}\n \n {% endfor %}\n \n \n {%- endfor -%}\n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n
    Nature of goods or services
    \u0637\u0628\u064a\u0639\u0629 \u0627\u0644\u0633\u0644\u0639 \u0623\u0648 \u0627\u0644\u062e\u062f\u0645\u0627\u062a
    \n Unit price
    \n \u0633\u0639\u0631 \u0627\u0644\u0648\u062d\u062f\u0629\n
    \n Quantity
    \n \u0627\u0644\u0643\u0645\u064a\u0629\n
    \n Taxable Amount
    \n \u0627\u0644\u0645\u0628\u0644\u063a \u0627\u0644\u062e\u0627\u0636\u0639 \u0644\u0644\u0636\u0631\u064a\u0628\u0629\n
    {{row.description}}\n Total
    \n \u0627\u0644\u0645\u062c\u0645\u0648\u0639\n
    {{ item.item_code }}{{ item.get_formatted(\"rate\") }}{{ item.qty }}{{ item.get_formatted(\"amount\") }}\n
    \n {%- if(data_object[item.item_code][0])-%}\n {{ frappe.format(data_object[item.item_code][0], {'fieldtype': 'Percent'}) }}\n {%- endif -%}\n \n {%- if(data_object[item.item_code][1])-%}\n {{ frappe.format_value(tax_amount, currency=doc.currency) }}\n {% set total.amount = total.amount + tax_amount %}\n {%- endif -%}\n
    \n
    {{ frappe.format_value(frappe.utils.flt(total.amount, doc.precision('total_taxes_and_charges')), currency=doc.currency) }}
    \n {{ doc.get_formatted(\"total\") }}
    \n {{ doc.get_formatted(\"total_taxes_and_charges\") }}\n
    \n \u0627\u0644\u0625\u062c\u0645\u0627\u0644\u064a \u0628\u0627\u0633\u062a\u062b\u0646\u0627\u0621 \u0636\u0631\u064a\u0628\u0629 \u0627\u0644\u0642\u064a\u0645\u0629 \u0627\u0644\u0645\u0636\u0627\u0641\u0629\n
    \n \u0625\u062c\u0645\u0627\u0644\u064a \u0636\u0631\u064a\u0628\u0629 \u0627\u0644\u0642\u064a\u0645\u0629 \u0627\u0644\u0645\u0636\u0627\u0641\u0629\n
    \n Total (Excluding VAT)\n
    \n Total VAT\n
    \n {{ doc.get_formatted(\"total\") }}
    \n {{ doc.get_formatted(\"total_taxes_and_charges\") }}\n
    {{ doc.get_formatted(\"grand_total\") }}\n \u0625\u062c\u0645\u0627\u0644\u064a \u0627\u0644\u0645\u0628\u0644\u063a \u0627\u0644\u0645\u0633\u062a\u062d\u0642Total Amount Due{{ doc.get_formatted(\"grand_total\") }}
    \n\n\t{%- if doc.terms -%}\n

    \n {{doc.terms}}\n

    \n\t{%- endif -%}\n
    \n", + "idx": 0, + "line_breaks": 0, + "margin_bottom": 15.0, + "margin_left": 15.0, + "margin_right": 15.0, + "margin_top": 15.0, + "modified": "2021-11-22 10:40:24.716932", + "modified_by": "Administrator", + "module": "Regional", + "name": "KSA VAT Invoice", + "owner": "Administrator", + "page_number": "Hide", + "print_format_builder": 0, + "print_format_builder_beta": 0, + "print_format_type": "Jinja", + "raw_printing": 0, + "show_section_headings": 0, + "standard": "Yes" +} \ No newline at end of file diff --git a/erpnext/regional/report/datev/datev.py b/erpnext/regional/report/datev/datev.py index c46c0df22c7..beac7ed65cd 100644 --- a/erpnext/regional/report/datev/datev.py +++ b/erpnext/regional/report/datev/datev.py @@ -1,4 +1,3 @@ -# coding: utf-8 """ Provide a report and downloadable CSV according to the German DATEV format. @@ -7,13 +6,11 @@ Provide a report and downloadable CSV according to the German DATEV format. - CSV download functionality `download_datev_csv` that provides a CSV file with all required columns. Used to import the data into the DATEV Software. """ -from __future__ import unicode_literals import json import frappe from frappe import _ -from six import string_types from erpnext.accounts.utils import get_fiscal_year from erpnext.regional.germany.utils.datev.datev_constants import ( @@ -351,7 +348,7 @@ def run_query(filters, extra_fields, extra_joins, extra_filters, as_dict=1): gl.posting_date as 'Belegdatum', gl.voucher_no as 'Belegfeld 1', - LEFT(gl.remarks, 60) as 'Buchungstext', + REPLACE(LEFT(gl.remarks, 60), '\n', ' ') as 'Buchungstext', gl.voucher_type as 'Beleginfo - Art 1', gl.voucher_no as 'Beleginfo - Inhalt 1', gl.against_voucher_type as 'Beleginfo - Art 2', @@ -546,7 +543,7 @@ def download_datev_csv(filters): Arguments / Params: filters -- dict of filters to be passed to the sql query """ - if isinstance(filters, string_types): + if isinstance(filters, str): filters = json.loads(filters) validate(filters) diff --git a/erpnext/regional/report/datev/test_datev.py b/erpnext/regional/report/datev/test_datev.py index b53889366f1..14d5495eed7 100644 --- a/erpnext/regional/report/datev/test_datev.py +++ b/erpnext/regional/report/datev/test_datev.py @@ -1,6 +1,3 @@ -# coding=utf-8 -from __future__ import unicode_literals - import zipfile from unittest import TestCase diff --git a/erpnext/regional/report/electronic_invoice_register/electronic_invoice_register.py b/erpnext/regional/report/electronic_invoice_register/electronic_invoice_register.py index f4ce7a77ad9..1ae3d16c97a 100644 --- a/erpnext/regional/report/electronic_invoice_register/electronic_invoice_register.py +++ b/erpnext/regional/report/electronic_invoice_register/electronic_invoice_register.py @@ -1,7 +1,6 @@ # Copyright (c) 2013, Frappe Technologies Pvt. Ltd. and contributors # For license information, please see license.txt -from __future__ import unicode_literals from erpnext.accounts.report.sales_register.sales_register import _execute diff --git a/erpnext/regional/report/eway_bill/eway_bill.py b/erpnext/regional/report/eway_bill/eway_bill.py index c78084f7dff..91a47674d7b 100644 --- a/erpnext/regional/report/eway_bill/eway_bill.py +++ b/erpnext/regional/report/eway_bill/eway_bill.py @@ -1,7 +1,6 @@ # Copyright (c) 2013, FinByz Tech Pvt. Ltd. and contributors # For license information, please see license.txt -from __future__ import unicode_literals import json import re diff --git a/erpnext/regional/report/fichier_des_ecritures_comptables_[fec]/fichier_des_ecritures_comptables_[fec].py b/erpnext/regional/report/fichier_des_ecritures_comptables_[fec]/fichier_des_ecritures_comptables_[fec].py index 9567916cd2a..59888ff94e7 100644 --- a/erpnext/regional/report/fichier_des_ecritures_comptables_[fec]/fichier_des_ecritures_comptables_[fec].py +++ b/erpnext/regional/report/fichier_des_ecritures_comptables_[fec]/fichier_des_ecritures_comptables_[fec].py @@ -1,7 +1,6 @@ # Copyright (c) 2018, Frappe Technologies Pvt. Ltd. and contributors # For license information, please see license.txt -from __future__ import unicode_literals import re diff --git a/erpnext/regional/report/gst_itemised_purchase_register/gst_itemised_purchase_register.py b/erpnext/regional/report/gst_itemised_purchase_register/gst_itemised_purchase_register.py index 092f72adf15..528868cf176 100644 --- a/erpnext/regional/report/gst_itemised_purchase_register/gst_itemised_purchase_register.py +++ b/erpnext/regional/report/gst_itemised_purchase_register/gst_itemised_purchase_register.py @@ -1,7 +1,6 @@ # Copyright (c) 2013, Frappe Technologies Pvt. Ltd. and contributors # For license information, please see license.txt -from __future__ import unicode_literals from erpnext.accounts.report.item_wise_purchase_register.item_wise_purchase_register import ( _execute, diff --git a/erpnext/regional/report/gst_itemised_sales_register/gst_itemised_sales_register.py b/erpnext/regional/report/gst_itemised_sales_register/gst_itemised_sales_register.py index 44f623bfae9..386e2197569 100644 --- a/erpnext/regional/report/gst_itemised_sales_register/gst_itemised_sales_register.py +++ b/erpnext/regional/report/gst_itemised_sales_register/gst_itemised_sales_register.py @@ -1,7 +1,6 @@ # Copyright (c) 2013, Frappe Technologies Pvt. Ltd. and contributors # For license information, please see license.txt -from __future__ import unicode_literals from erpnext.accounts.report.item_wise_sales_register.item_wise_sales_register import _execute diff --git a/erpnext/regional/report/gst_purchase_register/gst_purchase_register.py b/erpnext/regional/report/gst_purchase_register/gst_purchase_register.py index e9724441b17..2d994082c31 100644 --- a/erpnext/regional/report/gst_purchase_register/gst_purchase_register.py +++ b/erpnext/regional/report/gst_purchase_register/gst_purchase_register.py @@ -1,7 +1,6 @@ # Copyright (c) 2013, Frappe Technologies Pvt. Ltd. and contributors # For license information, please see license.txt -from __future__ import unicode_literals from erpnext.accounts.report.purchase_register.purchase_register import _execute diff --git a/erpnext/regional/report/gst_sales_register/gst_sales_register.py b/erpnext/regional/report/gst_sales_register/gst_sales_register.py index 6975af35854..a6f2b3dbf4d 100644 --- a/erpnext/regional/report/gst_sales_register/gst_sales_register.py +++ b/erpnext/regional/report/gst_sales_register/gst_sales_register.py @@ -1,7 +1,6 @@ # Copyright (c) 2013, Frappe Technologies Pvt. Ltd. and contributors # For license information, please see license.txt -from __future__ import unicode_literals from erpnext.accounts.report.sales_register.sales_register import _execute diff --git a/erpnext/regional/report/gstr_1/gstr_1.py b/erpnext/regional/report/gstr_1/gstr_1.py index e3e09ef8e56..11b684d3f6a 100644 --- a/erpnext/regional/report/gstr_1/gstr_1.py +++ b/erpnext/regional/report/gstr_1/gstr_1.py @@ -1,7 +1,6 @@ # Copyright (c) 2013, Frappe Technologies Pvt. Ltd. and contributors # For license information, please see license.txt -from __future__ import unicode_literals import json from datetime import date @@ -9,7 +8,6 @@ from datetime import date import frappe from frappe import _ from frappe.utils import flt, formatdate, getdate -from six import iteritems from erpnext.regional.india.utils import get_gst_accounts @@ -54,7 +52,7 @@ class Gstr1Report(object): self.get_invoice_items() self.get_items_based_on_tax_rate() self.invoice_fields = [d["fieldname"] for d in self.invoice_columns] - + self.get_data() return self.columns, self.data @@ -96,35 +94,36 @@ class Gstr1Report(object): def get_b2c_data(self): b2cs_output = {} - for inv, items_based_on_rate in self.items_based_on_tax_rate.items(): - invoice_details = self.invoices.get(inv) - for rate, items in items_based_on_rate.items(): - place_of_supply = invoice_details.get("place_of_supply") - ecommerce_gstin = invoice_details.get("ecommerce_gstin") + if self.invoices: + for inv, items_based_on_rate in self.items_based_on_tax_rate.items(): + invoice_details = self.invoices.get(inv) + for rate, items in items_based_on_rate.items(): + place_of_supply = invoice_details.get("place_of_supply") + ecommerce_gstin = invoice_details.get("ecommerce_gstin") - b2cs_output.setdefault((rate, place_of_supply, ecommerce_gstin),{ - "place_of_supply": "", - "ecommerce_gstin": "", - "rate": "", - "taxable_value": 0, - "cess_amount": 0, - "type": "", - "invoice_number": invoice_details.get("invoice_number"), - "posting_date": invoice_details.get("posting_date"), - "invoice_value": invoice_details.get("base_grand_total"), - }) + b2cs_output.setdefault((rate, place_of_supply, ecommerce_gstin), { + "place_of_supply": "", + "ecommerce_gstin": "", + "rate": "", + "taxable_value": 0, + "cess_amount": 0, + "type": "", + "invoice_number": invoice_details.get("invoice_number"), + "posting_date": invoice_details.get("posting_date"), + "invoice_value": invoice_details.get("base_grand_total"), + }) - row = b2cs_output.get((rate, place_of_supply, ecommerce_gstin)) - row["place_of_supply"] = place_of_supply - row["ecommerce_gstin"] = ecommerce_gstin - row["rate"] = rate - row["taxable_value"] += sum([abs(net_amount) - for item_code, net_amount in self.invoice_items.get(inv).items() if item_code in items]) - row["cess_amount"] += flt(self.invoice_cess.get(inv), 2) - row["type"] = "E" if ecommerce_gstin else "OE" + row = b2cs_output.get((rate, place_of_supply, ecommerce_gstin)) + row["place_of_supply"] = place_of_supply + row["ecommerce_gstin"] = ecommerce_gstin + row["rate"] = rate + row["taxable_value"] += sum([abs(net_amount) + for item_code, net_amount in self.invoice_items.get(inv).items() if item_code in items]) + row["cess_amount"] += flt(self.invoice_cess.get(inv), 2) + row["type"] = "E" if ecommerce_gstin else "OE" - for key, value in iteritems(b2cs_output): - self.data.append(value) + for key, value in b2cs_output.items(): + self.data.append(value) def get_row_data_for_invoice(self, invoice, invoice_details, tax_rate, items): row = [] @@ -171,12 +170,6 @@ class Gstr1Report(object): self.invoices = frappe._dict() conditions = self.get_conditions() - company_gstins = get_company_gstin_number(self.filters.get('company'), all_gstins=True) - - self.filters.update({ - 'company_gstins': company_gstins - }) - invoice_data = frappe.db.sql(""" select {select_columns} @@ -212,7 +205,7 @@ class Gstr1Report(object): if self.filters.get("type_of_business") == "B2B": - conditions += "AND IFNULL(gst_category, '') in ('Registered Regular', 'Deemed Export', 'SEZ') AND is_return != 1" + conditions += "AND IFNULL(gst_category, '') in ('Registered Regular', 'Deemed Export', 'SEZ') AND is_return != 1 AND is_debit_note !=1" if self.filters.get("type_of_business") in ("B2C Large", "B2C Small"): b2c_limit = frappe.db.get_single_value('GST Settings', 'b2c_limit') @@ -221,7 +214,7 @@ class Gstr1Report(object): if self.filters.get("type_of_business") == "B2C Large": conditions += """ AND ifnull(SUBSTR(place_of_supply, 1, 2),'') != ifnull(SUBSTR(company_gstin, 1, 2),'') - AND grand_total > {0} AND is_return != 1 and gst_category ='Unregistered' """.format(flt(b2c_limit)) + AND grand_total > {0} AND is_return != 1 AND is_debit_note !=1 AND gst_category ='Unregistered' """.format(flt(b2c_limit)) elif self.filters.get("type_of_business") == "B2C Small": conditions += """ AND ( @@ -234,13 +227,13 @@ class Gstr1Report(object): elif self.filters.get("type_of_business") == "CDNR-UNREG": b2c_limit = frappe.db.get_single_value('GST Settings', 'b2c_limit') conditions += """ AND ifnull(SUBSTR(place_of_supply, 1, 2),'') != ifnull(SUBSTR(company_gstin, 1, 2),'') - AND ABS(grand_total) > {0} AND (is_return = 1 OR is_debit_note = 1) - AND IFNULL(gst_category, '') in ('Unregistered', 'Overseas')""".format(flt(b2c_limit)) + AND (is_return = 1 OR is_debit_note = 1) + AND IFNULL(gst_category, '') in ('Unregistered', 'Overseas')""" elif self.filters.get("type_of_business") == "EXPORT": conditions += """ AND is_return !=1 and gst_category = 'Overseas' """ - conditions += " AND IFNULL(billing_address_gstin, '') NOT IN %(company_gstins)s" + conditions += " AND IFNULL(billing_address_gstin, '') != company_gstin" return conditions @@ -255,18 +248,17 @@ class Gstr1Report(object): """ % (self.doctype, ', '.join(['%s']*len(self.invoices))), tuple(self.invoices), as_dict=1) for d in items: - if d.item_code not in self.invoice_items.get(d.parent, {}): - self.invoice_items.setdefault(d.parent, {}).setdefault(d.item_code, 0.0) - self.invoice_items[d.parent][d.item_code] += d.get('taxable_value', 0) or d.get('base_net_amount', 0) + self.invoice_items.setdefault(d.parent, {}).setdefault(d.item_code, 0.0) + self.invoice_items[d.parent][d.item_code] += d.get('taxable_value', 0) or d.get('base_net_amount', 0) - item_tax_rate = {} + item_tax_rate = {} - if d.item_tax_rate: - item_tax_rate = json.loads(d.item_tax_rate) + if d.item_tax_rate: + item_tax_rate = json.loads(d.item_tax_rate) - for account, rate in item_tax_rate.items(): - tax_rate_dict = self.item_tax_rate.setdefault(d.parent, {}).setdefault(d.item_code, []) - tax_rate_dict.append(rate) + for account, rate in item_tax_rate.items(): + tax_rate_dict = self.item_tax_rate.setdefault(d.parent, {}).setdefault(d.item_code, []) + tax_rate_dict.append(rate) def get_items_based_on_tax_rate(self): self.tax_details = frappe.db.sql(""" @@ -323,7 +315,7 @@ class Gstr1Report(object): + "
    " + "
    ".join(unidentified_gst_accounts), alert=True) # Build itemised tax for export invoices where tax table is blank - for invoice, items in iteritems(self.invoice_items): + for invoice, items in self.invoice_items.items(): if invoice not in self.items_based_on_tax_rate and invoice not in unidentified_gst_accounts_invoice \ and self.invoices.get(invoice, {}).get('export_type') == "Without Payment of Tax" \ and self.invoices.get(invoice, {}).get('gst_category') == "Overseas": @@ -713,7 +705,7 @@ class Gstr1Report(object): "width": 100 } ] - + self.columns = self.invoice_columns + self.tax_columns + self.other_columns @frappe.whitelist() @@ -788,7 +780,7 @@ def get_b2b_json(res, gstin): b2b_item, inv = {"ctin": gst_in, "inv": []}, [] if not gst_in: continue - for number, invoice in iteritems(res[gst_in]): + for number, invoice in res[gst_in].items(): if not invoice[0]["place_of_supply"]: frappe.throw(_("""{0} not entered in Invoice {1}. Please update and try again""").format(frappe.bold("Place Of Supply"), @@ -857,7 +849,7 @@ def get_b2cs_json(data, gstin): def get_advances_json(data, gstin): company_state_number = gstin[0:2] out = [] - for place_of_supply, items in iteritems(data): + for place_of_supply, items in data.items(): supply_type = "INTRA" if company_state_number == place_of_supply.split('-')[0] else "INTER" row = { "pos": place_of_supply.split('-')[0], @@ -939,7 +931,7 @@ def get_cdnr_reg_json(res, gstin): cdnr_item, inv = {"ctin": gst_in, "nt": []}, [] if not gst_in: continue - for number, invoice in iteritems(res[gst_in]): + for number, invoice in res[gst_in].items(): if not invoice[0]["place_of_supply"]: frappe.throw(_("""{0} not entered in Invoice {1}. Please update and try again""").format(frappe.bold("Place Of Supply"), @@ -970,7 +962,7 @@ def get_cdnr_reg_json(res, gstin): def get_cdnr_unreg_json(res, gstin): out = [] - for invoice, items in iteritems(res): + for invoice, items in res.items(): inv_item = { "nt_num": items[0]["invoice_number"], "nt_dt": getdate(items[0]["posting_date"]).strftime('%d-%m-%Y'), @@ -1050,6 +1042,7 @@ def get_company_gstin_number(company, address=None, all_gstins=False): ["Dynamic Link", "link_doctype", "=", "Company"], ["Dynamic Link", "link_name", "=", company], ["Dynamic Link", "parenttype", "=", "Address"], + ["gstin", "!=", ''] ] gstin = frappe.get_all("Address", filters=filters, pluck="gstin", order_by="is_primary_address desc") if gstin and not all_gstins: diff --git a/erpnext/regional/report/gstr_2/gstr_2.py b/erpnext/regional/report/gstr_2/gstr_2.py index 5e44955ce30..47c856dfaae 100644 --- a/erpnext/regional/report/gstr_2/gstr_2.py +++ b/erpnext/regional/report/gstr_2/gstr_2.py @@ -1,7 +1,6 @@ # Copyright (c) 2013, Frappe Technologies Pvt. Ltd. and contributors # For license information, please see license.txt -from __future__ import unicode_literals from datetime import date diff --git a/erpnext/regional/report/hsn_wise_summary_of_outward_supplies/hsn_wise_summary_of_outward_supplies.py b/erpnext/regional/report/hsn_wise_summary_of_outward_supplies/hsn_wise_summary_of_outward_supplies.py index 7a938c7e0f2..e03ad374aef 100644 --- a/erpnext/regional/report/hsn_wise_summary_of_outward_supplies/hsn_wise_summary_of_outward_supplies.py +++ b/erpnext/regional/report/hsn_wise_summary_of_outward_supplies/hsn_wise_summary_of_outward_supplies.py @@ -1,7 +1,6 @@ # Copyright (c) 2016, Frappe Technologies Pvt. Ltd. and Contributors # License: GNU General Public License v3. See license.txt -from __future__ import unicode_literals import json @@ -9,7 +8,6 @@ import frappe from frappe import _ from frappe.model.meta import get_field_precision from frappe.utils import cstr, flt, getdate -from six import iteritems import erpnext from erpnext.regional.india.utils import get_gst_accounts @@ -213,7 +211,7 @@ def get_merged_data(columns, data): else: merged_hsn_dict[row[0]][d['fieldname']] = row[i] - for key, value in iteritems(merged_hsn_dict): + for key, value in merged_hsn_dict.items(): result.append(value) return result diff --git a/erpnext/healthcare/doctype/fee_validity/__init__.py b/erpnext/regional/report/ksa_vat/__init__.py similarity index 100% rename from erpnext/healthcare/doctype/fee_validity/__init__.py rename to erpnext/regional/report/ksa_vat/__init__.py diff --git a/erpnext/regional/report/ksa_vat/ksa_vat.js b/erpnext/regional/report/ksa_vat/ksa_vat.js new file mode 100644 index 00000000000..59e72c3e638 --- /dev/null +++ b/erpnext/regional/report/ksa_vat/ksa_vat.js @@ -0,0 +1,59 @@ +// Copyright (c) 2016, Havenir Solutions and contributors +// For license information, please see license.txt +/* eslint-disable */ + +frappe.query_reports["KSA VAT"] = { + onload() { + frappe.breadcrumbs.add('Accounts'); + }, + "filters": [ + { + "fieldname": "company", + "label": __("Company"), + "fieldtype": "Link", + "options": "Company", + "reqd": 1, + "default": frappe.defaults.get_user_default("Company") + }, + { + "fieldname": "from_date", + "label": __("From Date"), + "fieldtype": "Date", + "reqd": 1, + "default": frappe.datetime.add_months(frappe.datetime.get_today(), -1), + }, + { + "fieldname": "to_date", + "label": __("To Date"), + "fieldtype": "Date", + "reqd": 1, + "default": frappe.datetime.get_today() + } + ], + "formatter": function(value, row, column, data, default_formatter) { + if (data + && (data.title=='VAT on Sales' || data.title=='VAT on Purchases') + && data.title==value) { + value = $(`${value}`); + var $value = $(value).css("font-weight", "bold"); + value = $value.wrap("

    ").parent().html(); + return value + }else if (data.title=='Grand Total'){ + if (data.title==value) { + value = $(`${value}`); + var $value = $(value).css("font-weight", "bold"); + value = $value.wrap("

    ").parent().html(); + return value + }else{ + value = default_formatter(value, row, column, data); + value = $(`${value}`); + var $value = $(value).css("font-weight", "bold"); + value = $value.wrap("

    ").parent().html(); + return value + } + }else{ + value = default_formatter(value, row, column, data); + return value; + } + }, +}; diff --git a/erpnext/regional/report/ksa_vat/ksa_vat.json b/erpnext/regional/report/ksa_vat/ksa_vat.json new file mode 100644 index 00000000000..036e2603103 --- /dev/null +++ b/erpnext/regional/report/ksa_vat/ksa_vat.json @@ -0,0 +1,32 @@ +{ + "add_total_row": 0, + "columns": [], + "creation": "2021-07-13 08:54:38.000949", + "disable_prepared_report": 1, + "disabled": 1, + "docstatus": 0, + "doctype": "Report", + "filters": [], + "idx": 0, + "is_standard": "Yes", + "modified": "2021-08-26 04:14:37.202594", + "modified_by": "Administrator", + "module": "Regional", + "name": "KSA VAT", + "owner": "Administrator", + "prepared_report": 1, + "ref_doctype": "GL Entry", + "report_name": "KSA VAT", + "report_type": "Script Report", + "roles": [ + { + "role": "System Manager" + }, + { + "role": "Accounts Manager" + }, + { + "role": "Accounts User" + } + ] +} \ No newline at end of file diff --git a/erpnext/regional/report/ksa_vat/ksa_vat.py b/erpnext/regional/report/ksa_vat/ksa_vat.py new file mode 100644 index 00000000000..b41b2b0428f --- /dev/null +++ b/erpnext/regional/report/ksa_vat/ksa_vat.py @@ -0,0 +1,175 @@ +# Copyright (c) 2013, Havenir Solutions and contributors +# For license information, please see license.txt + + +import json + +import frappe +from frappe import _ +from frappe.utils import get_url_to_list + + +def execute(filters=None): + columns = columns = get_columns() + data = get_data(filters) + return columns, data + +def get_columns(): + return [ + { + "fieldname": "title", + "label": _("Title"), + "fieldtype": "Data", + "width": 300 + }, + { + "fieldname": "amount", + "label": _("Amount (SAR)"), + "fieldtype": "Currency", + "width": 150, + }, + { + "fieldname": "adjustment_amount", + "label": _("Adjustment (SAR)"), + "fieldtype": "Currency", + "width": 150, + }, + { + "fieldname": "vat_amount", + "label": _("VAT Amount (SAR)"), + "fieldtype": "Currency", + "width": 150, + } + ] + +def get_data(filters): + data = [] + + # Validate if vat settings exist + company = filters.get('company') + if frappe.db.exists('KSA VAT Setting', company) is None: + url = get_url_to_list('KSA VAT Setting') + frappe.msgprint(_('Create KSA VAT Setting for this company').format(url)) + return data + + ksa_vat_setting = frappe.get_doc('KSA VAT Setting', company) + + # Sales Heading + append_data(data, 'VAT on Sales', '', '', '') + + grand_total_taxable_amount = 0 + grand_total_taxable_adjustment_amount = 0 + grand_total_tax = 0 + + for vat_setting in ksa_vat_setting.ksa_vat_sales_accounts: + total_taxable_amount, total_taxable_adjustment_amount, \ + total_tax = get_tax_data_for_each_vat_setting(vat_setting, filters, 'Sales Invoice') + + # Adding results to data + append_data(data, vat_setting.title, total_taxable_amount, + total_taxable_adjustment_amount, total_tax) + + grand_total_taxable_amount += total_taxable_amount + grand_total_taxable_adjustment_amount += total_taxable_adjustment_amount + grand_total_tax += total_tax + + # Sales Grand Total + append_data(data, 'Grand Total', grand_total_taxable_amount, + grand_total_taxable_adjustment_amount, grand_total_tax) + + # Blank Line + append_data(data, '', '', '', '') + + # Purchase Heading + append_data(data, 'VAT on Purchases', '', '', '') + + grand_total_taxable_amount = 0 + grand_total_taxable_adjustment_amount = 0 + grand_total_tax = 0 + + for vat_setting in ksa_vat_setting.ksa_vat_purchase_accounts: + total_taxable_amount, total_taxable_adjustment_amount, \ + total_tax = get_tax_data_for_each_vat_setting(vat_setting, filters, 'Purchase Invoice') + + # Adding results to data + append_data(data, vat_setting.title, total_taxable_amount, + total_taxable_adjustment_amount, total_tax) + + grand_total_taxable_amount += total_taxable_amount + grand_total_taxable_adjustment_amount += total_taxable_adjustment_amount + grand_total_tax += total_tax + + # Purchase Grand Total + append_data(data, 'Grand Total', grand_total_taxable_amount, + grand_total_taxable_adjustment_amount, grand_total_tax) + + return data + +def get_tax_data_for_each_vat_setting(vat_setting, filters, doctype): + ''' + (KSA, {filters}, 'Sales Invoice') => 500, 153, 10 \n + calculates and returns \n + total_taxable_amount, total_taxable_adjustment_amount, total_tax''' + from_date = filters.get('from_date') + to_date = filters.get('to_date') + + # Initiate variables + total_taxable_amount = 0 + total_taxable_adjustment_amount = 0 + total_tax = 0 + # Fetch All Invoices + invoices = frappe.get_all(doctype, + filters ={ + 'docstatus': 1, + 'posting_date': ['between', [from_date, to_date]] + }, fields =['name', 'is_return']) + + for invoice in invoices: + invoice_items = frappe.get_all(f'{doctype} Item', + filters ={ + 'docstatus': 1, + 'parent': invoice.name, + 'item_tax_template': vat_setting.item_tax_template + }, fields =['item_code', 'net_amount']) + + for item in invoice_items: + # Summing up total taxable amount + if invoice.is_return == 0: + total_taxable_amount += item.net_amount + + if invoice.is_return == 1: + total_taxable_adjustment_amount += item.net_amount + + # Summing up total tax + total_tax += get_tax_amount(item.item_code, vat_setting.account, doctype, invoice.name) + + return total_taxable_amount, total_taxable_adjustment_amount, total_tax + + + +def append_data(data, title, amount, adjustment_amount, vat_amount): + """Returns data with appended value.""" + data.append({"title": _(title), "amount": amount, "adjustment_amount": adjustment_amount, "vat_amount": vat_amount}) + +def get_tax_amount(item_code, account_head, doctype, parent): + if doctype == 'Sales Invoice': + tax_doctype = 'Sales Taxes and Charges' + + elif doctype == 'Purchase Invoice': + tax_doctype = 'Purchase Taxes and Charges' + + item_wise_tax_detail = frappe.get_value(tax_doctype, { + 'docstatus': 1, + 'parent': parent, + 'account_head': account_head + }, 'item_wise_tax_detail') + + tax_amount = 0 + if item_wise_tax_detail and len(item_wise_tax_detail) > 0: + item_wise_tax_detail = json.loads(item_wise_tax_detail) + for key, value in item_wise_tax_detail.items(): + if key == item_code: + tax_amount = value[1] + break + + return tax_amount diff --git a/erpnext/regional/report/professional_tax_deductions/professional_tax_deductions.py b/erpnext/regional/report/professional_tax_deductions/professional_tax_deductions.py index 5300b928925..def43798289 100644 --- a/erpnext/regional/report/professional_tax_deductions/professional_tax_deductions.py +++ b/erpnext/regional/report/professional_tax_deductions/professional_tax_deductions.py @@ -1,7 +1,6 @@ # Copyright (c) 2013, Frappe Technologies Pvt. Ltd. and contributors # For license information, please see license.txt -from __future__ import unicode_literals import frappe from frappe import _ diff --git a/erpnext/regional/report/provident_fund_deductions/provident_fund_deductions.py b/erpnext/regional/report/provident_fund_deductions/provident_fund_deductions.py index ae5d6b90b4e..190f408fe0e 100644 --- a/erpnext/regional/report/provident_fund_deductions/provident_fund_deductions.py +++ b/erpnext/regional/report/provident_fund_deductions/provident_fund_deductions.py @@ -1,7 +1,6 @@ # Copyright (c) 2013, Frappe Technologies Pvt. Ltd. and contributors # For license information, please see license.txt -from __future__ import unicode_literals import frappe from frappe import _ diff --git a/erpnext/regional/report/uae_vat_201/test_uae_vat_201.py b/erpnext/regional/report/uae_vat_201/test_uae_vat_201.py index e19aeaa0eff..41336873ac9 100644 --- a/erpnext/regional/report/uae_vat_201/test_uae_vat_201.py +++ b/erpnext/regional/report/uae_vat_201/test_uae_vat_201.py @@ -1,6 +1,3 @@ -# coding=utf-8 -from __future__ import unicode_literals - from unittest import TestCase import frappe diff --git a/erpnext/regional/report/uae_vat_201/uae_vat_201.py b/erpnext/regional/report/uae_vat_201/uae_vat_201.py index f4c049d1623..f8379aa17ab 100644 --- a/erpnext/regional/report/uae_vat_201/uae_vat_201.py +++ b/erpnext/regional/report/uae_vat_201/uae_vat_201.py @@ -1,7 +1,6 @@ # Copyright (c) 2013, Frappe Technologies Pvt. Ltd. and contributors # For license information, please see license.txt -from __future__ import unicode_literals import frappe from frappe import _ @@ -122,7 +121,7 @@ def get_total_emiratewise(filters): try: return frappe.db.sql(""" select - s.vat_emirate as emirate, sum(i.base_amount) as total, sum(s.total_taxes_and_charges) + s.vat_emirate as emirate, sum(i.base_amount) as total, sum(i.tax_amount) from `tabSales Invoice Item` i inner join `tabSales Invoice` s on diff --git a/erpnext/regional/report/vat_audit_report/test_vat_audit_report.py b/erpnext/regional/report/vat_audit_report/test_vat_audit_report.py index 77beff36ecd..f22abae1ff8 100644 --- a/erpnext/regional/report/vat_audit_report/test_vat_audit_report.py +++ b/erpnext/regional/report/vat_audit_report/test_vat_audit_report.py @@ -1,7 +1,6 @@ # Copyright (c) 2021, Frappe Technologies Pvt. Ltd. and contributors # For license information, please see license.txt -from __future__ import unicode_literals from unittest import TestCase diff --git a/erpnext/regional/report/vat_audit_report/vat_audit_report.py b/erpnext/regional/report/vat_audit_report/vat_audit_report.py index 3637bcaf439..5a281a4cbb2 100644 --- a/erpnext/regional/report/vat_audit_report/vat_audit_report.py +++ b/erpnext/regional/report/vat_audit_report/vat_audit_report.py @@ -1,7 +1,6 @@ # Copyright (c) 2021, Frappe Technologies Pvt. Ltd. and contributors # For license information, please see license.txt -from __future__ import unicode_literals import json diff --git a/erpnext/regional/saudi_arabia/setup.py b/erpnext/regional/saudi_arabia/setup.py index 9b3677d2c64..38a089c6326 100644 --- a/erpnext/regional/saudi_arabia/setup.py +++ b/erpnext/regional/saudi_arabia/setup.py @@ -1,11 +1,63 @@ # Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors # License: GNU General Public License v3. See license.txt -from __future__ import unicode_literals - -from erpnext.regional.united_arab_emirates.setup import make_custom_fields, add_print_formats - +import frappe +from frappe.permissions import add_permission, update_permission_property +from erpnext.regional.united_arab_emirates.setup import make_custom_fields as uae_custom_fields, add_print_formats +from erpnext.regional.saudi_arabia.wizard.operations.setup_ksa_vat_setting import create_ksa_vat_setting +from frappe.custom.doctype.custom_field.custom_field import create_custom_fields def setup(company=None, patch=True): - make_custom_fields() + uae_custom_fields() add_print_formats() + add_permissions() + make_custom_fields() + +def add_permissions(): + """Add Permissions for KSA VAT Setting.""" + add_permission('KSA VAT Setting', 'All', 0) + for role in ('Accounts Manager', 'Accounts User', 'System Manager'): + add_permission('KSA VAT Setting', role, 0) + update_permission_property('KSA VAT Setting', role, 0, 'write', 1) + update_permission_property('KSA VAT Setting', role, 0, 'create', 1) + + """Enable KSA VAT Report""" + frappe.db.set_value('Report', 'KSA VAT', 'disabled', 0) + +def make_custom_fields(): + """Create Custom fields + - QR code Image file + - Company Name in Arabic + - Address in Arabic + """ + custom_fields = { + 'Sales Invoice': [ + dict( + fieldname='qr_code', + label='QR Code', + fieldtype='Attach Image', + read_only=1, no_copy=1, hidden=1 + ) + ], + 'Address': [ + dict( + fieldname='address_in_arabic', + label='Address in Arabic', + fieldtype='Data', + insert_after='address_line2' + ) + ], + 'Company': [ + dict( + fieldname='company_name_in_arabic', + label='Company Name In Arabic', + fieldtype='Data', + insert_after='company_name' + ) + ] + } + + create_custom_fields(custom_fields, update=True) + +def update_regional_tax_settings(country, company): + create_ksa_vat_setting(company) diff --git a/erpnext/regional/saudi_arabia/utils.py b/erpnext/regional/saudi_arabia/utils.py new file mode 100644 index 00000000000..a2f634ee22c --- /dev/null +++ b/erpnext/regional/saudi_arabia/utils.py @@ -0,0 +1,92 @@ +import io +import os + +import frappe +from pyqrcode import create as qr_create + +from erpnext import get_region + + +def create_qr_code(doc, method): + """Create QR Code after inserting Sales Inv + """ + + region = get_region(doc.company) + if region not in ['Saudi Arabia']: + return + + # if QR Code field not present, do nothing + if not hasattr(doc, 'qr_code'): + return + + # Don't create QR Code if it already exists + qr_code = doc.get("qr_code") + if qr_code and frappe.db.exists({"doctype": "File", "file_url": qr_code}): + return + + meta = frappe.get_meta('Sales Invoice') + + for field in meta.get_image_fields(): + if field.fieldname == 'qr_code': + from urllib.parse import urlencode + + # Creating public url to print format + default_print_format = frappe.db.get_value('Property Setter', dict(property='default_print_format', doc_type=doc.doctype), "value") + + # System Language + language = frappe.get_system_settings('language') + + params = urlencode({ + 'format': default_print_format or 'Standard', + '_lang': language, + 'key': doc.get_signature() + }) + + # creating qr code for the url + url = f"{ frappe.utils.get_url() }/{ doc.doctype }/{ doc.name }?{ params }" + qr_image = io.BytesIO() + url = qr_create(url, error='L') + url.png(qr_image, scale=2, quiet_zone=1) + + # making file + filename = f"QR-CODE-{doc.name}.png".replace(os.path.sep, "__") + _file = frappe.get_doc({ + "doctype": "File", + "file_name": filename, + "is_private": 0, + "content": qr_image.getvalue(), + "attached_to_doctype": doc.get("doctype"), + "attached_to_name": doc.get("name"), + "attached_to_field": "qr_code" + }) + + _file.save() + + # assigning to document + doc.db_set('qr_code', _file.file_url) + doc.notify_update() + + break + + +def delete_qr_code_file(doc, method): + """Delete QR Code on deleted sales invoice""" + + region = get_region(doc.company) + if region not in ['Saudi Arabia']: + return + + if hasattr(doc, 'qr_code'): + if doc.get('qr_code'): + file_doc = frappe.get_list('File', { + 'file_url': doc.get('qr_code') + }) + if len(file_doc): + frappe.delete_doc('File', file_doc[0].name) + +def delete_vat_settings_for_company(doc, method): + if doc.country != 'Saudi Arabia': + return + + settings_doc = frappe.get_doc('KSA VAT Setting', {'company': doc.name}) + settings_doc.delete() \ No newline at end of file diff --git a/erpnext/healthcare/doctype/fee_validity_reference/__init__.py b/erpnext/regional/saudi_arabia/wizard/__init__.py similarity index 100% rename from erpnext/healthcare/doctype/fee_validity_reference/__init__.py rename to erpnext/regional/saudi_arabia/wizard/__init__.py diff --git a/erpnext/healthcare/doctype/healthcare_practitioner/__init__.py b/erpnext/regional/saudi_arabia/wizard/data/__init__.py similarity index 100% rename from erpnext/healthcare/doctype/healthcare_practitioner/__init__.py rename to erpnext/regional/saudi_arabia/wizard/data/__init__.py diff --git a/erpnext/regional/saudi_arabia/wizard/data/ksa_vat_settings.json b/erpnext/regional/saudi_arabia/wizard/data/ksa_vat_settings.json new file mode 100644 index 00000000000..60951a9ceca --- /dev/null +++ b/erpnext/regional/saudi_arabia/wizard/data/ksa_vat_settings.json @@ -0,0 +1,47 @@ +[ + { + "type": "Sales Account", + "accounts": [ + { + "title": "Standard rated Sales", + "item_tax_template": "KSA VAT 5%", + "account": "VAT 5%" + }, + { + "title": "Zero rated domestic sales", + "item_tax_template": "KSA VAT Zero", + "account": "VAT Zero" + }, + { + "title": "Exempted sales", + "item_tax_template": "KSA VAT Exempted", + "account": "VAT Exempted" + } + ] + }, + { + "type": "Purchase Account", + "accounts": [ + { + "title": "Standard rated domestic purchases", + "item_tax_template": "KSA VAT 5%", + "account": "VAT 5%" + }, + { + "title": "Imports subject to VAT paid at customs", + "item_tax_template": "KSA Excise 50%", + "account": "Excise 50%" + }, + { + "title": "Zero rated purchases", + "item_tax_template": "KSA VAT Zero", + "account": "VAT Zero" + }, + { + "title": "Exempted purchases", + "item_tax_template": "KSA VAT Exempted", + "account": "VAT Exempted" + } + ] + } +] \ No newline at end of file diff --git a/erpnext/healthcare/doctype/healthcare_schedule_time_slot/__init__.py b/erpnext/regional/saudi_arabia/wizard/operations/__init__.py similarity index 100% rename from erpnext/healthcare/doctype/healthcare_schedule_time_slot/__init__.py rename to erpnext/regional/saudi_arabia/wizard/operations/__init__.py diff --git a/erpnext/regional/saudi_arabia/wizard/operations/setup_ksa_vat_setting.py b/erpnext/regional/saudi_arabia/wizard/operations/setup_ksa_vat_setting.py new file mode 100644 index 00000000000..97300dc3782 --- /dev/null +++ b/erpnext/regional/saudi_arabia/wizard/operations/setup_ksa_vat_setting.py @@ -0,0 +1,43 @@ +import json +import os + +import frappe + + +def create_ksa_vat_setting(company): + """On creation of first company. Creates KSA VAT Setting""" + + company = frappe.get_doc('Company', company) + + file_path = os.path.join(os.path.dirname(__file__), '..', 'data', 'ksa_vat_settings.json') + with open(file_path, 'r') as json_file: + account_data = json.load(json_file) + + # Creating KSA VAT Setting + ksa_vat_setting = frappe.get_doc({ + 'doctype': 'KSA VAT Setting', + 'company': company.name + }) + + for data in account_data: + if data['type'] == 'Sales Account': + for row in data['accounts']: + item_tax_template = row['item_tax_template'] + account = row['account'] + ksa_vat_setting.append('ksa_vat_sales_accounts', { + 'title': row['title'], + 'item_tax_template': f'{item_tax_template} - {company.abbr}', + 'account': f'{account} - {company.abbr}' + }) + + elif data['type'] == 'Purchase Account': + for row in data['accounts']: + item_tax_template = row['item_tax_template'] + account = row['account'] + ksa_vat_setting.append('ksa_vat_purchase_accounts', { + 'title': row['title'], + 'item_tax_template': f'{item_tax_template} - {company.abbr}', + 'account': f'{account} - {company.abbr}' + }) + + ksa_vat_setting.save() diff --git a/erpnext/regional/south_africa/setup.py b/erpnext/regional/south_africa/setup.py index 8a75987c3d7..6af135b960a 100644 --- a/erpnext/regional/south_africa/setup.py +++ b/erpnext/regional/south_africa/setup.py @@ -1,7 +1,6 @@ # Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors # License: GNU General Public License v3. See license.txt -from __future__ import unicode_literals import frappe from frappe.custom.doctype.custom_field.custom_field import create_custom_fields diff --git a/erpnext/regional/turkey/setup.py b/erpnext/regional/turkey/setup.py index 2396aab91f5..1d3770aefcb 100644 --- a/erpnext/regional/turkey/setup.py +++ b/erpnext/regional/turkey/setup.py @@ -1,4 +1,2 @@ -from __future__ import unicode_literals - def setup(company=None, patch=True): pass diff --git a/erpnext/regional/united_arab_emirates/setup.py b/erpnext/regional/united_arab_emirates/setup.py index 8b1905051c5..922443b924a 100644 --- a/erpnext/regional/united_arab_emirates/setup.py +++ b/erpnext/regional/united_arab_emirates/setup.py @@ -1,7 +1,6 @@ # Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors # License: GNU General Public License v3. See license.txt -from __future__ import unicode_literals import frappe from frappe.custom.doctype.custom_field.custom_field import create_custom_fields diff --git a/erpnext/regional/united_arab_emirates/utils.py b/erpnext/regional/united_arab_emirates/utils.py index 66a96514fc1..f350ec4ec2c 100644 --- a/erpnext/regional/united_arab_emirates/utils.py +++ b/erpnext/regional/united_arab_emirates/utils.py @@ -1,9 +1,6 @@ -from __future__ import unicode_literals - import frappe from frappe import _ from frappe.utils import flt, money_in_words, round_based_on_smallest_currency_fraction -from six import iteritems import erpnext from erpnext.controllers.taxes_and_totals import get_itemised_tax @@ -24,7 +21,7 @@ def update_itemised_tax_data(doc): # First check if tax rate is present # If not then look up in item_wise_tax_detail if item_tax_rate: - for account, rate in iteritems(item_tax_rate): + for account, rate in item_tax_rate.items(): tax_rate += rate elif row.item_code and itemised_tax.get(row.item_code): tax_rate = sum([tax.get('tax_rate', 0) for d, tax in itemised_tax.get(row.item_code).items()]) diff --git a/erpnext/regional/united_states/setup.py b/erpnext/regional/united_states/setup.py index 9c183af1d13..db6a9c35475 100644 --- a/erpnext/regional/united_states/setup.py +++ b/erpnext/regional/united_states/setup.py @@ -1,7 +1,6 @@ # Copyright (c) 2018, Frappe Technologies Pvt. Ltd. and Contributors # License: GNU General Public License v3. See license.txt -from __future__ import unicode_literals import frappe import os import json @@ -14,30 +13,9 @@ def setup(company=None, patch=True): setup_company_independent_fixtures(patch=patch) def setup_company_independent_fixtures(company=None, patch=True): - add_product_tax_categories() make_custom_fields() - add_permissions() - frappe.enqueue('erpnext.regional.united_states.setup.add_product_tax_categories', now=False) add_print_formats() -# Product Tax categories imported from taxjar api -def add_product_tax_categories(): - with open(os.path.join(os.path.dirname(__file__), 'product_tax_category_data.json'), 'r') as f: - tax_categories = json.loads(f.read()) - create_tax_categories(tax_categories['categories']) - -def create_tax_categories(data): - for d in data: - tax_category = frappe.new_doc('Product Tax Category') - tax_category.description = d.get("description") - tax_category.product_tax_code = d.get("product_tax_code") - tax_category.category_name = d.get("name") - try: - tax_category.db_insert() - except frappe.DuplicateEntryError: - pass - - def make_custom_fields(update=True): custom_fields = { 'Supplier': [ @@ -59,29 +37,10 @@ def make_custom_fields(update=True): 'Quotation': [ dict(fieldname='exempt_from_sales_tax', fieldtype='Check', insert_after='taxes_and_charges', label='Is customer exempted from sales tax?') - ], - 'Sales Invoice Item': [ - dict(fieldname='product_tax_category', fieldtype='Link', insert_after='description', options='Product Tax Category', - label='Product Tax Category', fetch_from='item_code.product_tax_category'), - dict(fieldname='tax_collectable', fieldtype='Currency', insert_after='net_amount', - label='Tax Collectable', read_only=1), - dict(fieldname='taxable_amount', fieldtype='Currency', insert_after='tax_collectable', - label='Taxable Amount', read_only=1) - ], - 'Item': [ - dict(fieldname='product_tax_category', fieldtype='Link', insert_after='item_group', options='Product Tax Category', - label='Product Tax Category') ] } create_custom_fields(custom_fields, update=update) -def add_permissions(): - doctype = "Product Tax Category" - for role in ('Accounts Manager', 'Accounts User', 'System Manager','Item Manager', 'Stock Manager'): - add_permission(doctype, role, 0) - update_permission_property(doctype, role, 0, 'write', 1) - update_permission_property(doctype, role, 0, 'create', 1) - def add_print_formats(): frappe.reload_doc("regional", "print_format", "irs_1099_form") frappe.db.set_value("Print Format", "IRS 1099 Form", "disabled", 0) diff --git a/erpnext/regional/united_states/test_united_states.py b/erpnext/regional/united_states/test_united_states.py index 19e9a3546f8..652b4835a18 100644 --- a/erpnext/regional/united_states/test_united_states.py +++ b/erpnext/regional/united_states/test_united_states.py @@ -1,6 +1,5 @@ # Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors # License: GNU General Public License v3. See license.txt -from __future__ import unicode_literals import unittest diff --git a/erpnext/restaurant/doctype/restaurant/restaurant.py b/erpnext/restaurant/doctype/restaurant/restaurant.py index 486afc3a11e..67838d29a37 100644 --- a/erpnext/restaurant/doctype/restaurant/restaurant.py +++ b/erpnext/restaurant/doctype/restaurant/restaurant.py @@ -1,8 +1,6 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2017, Frappe Technologies Pvt. Ltd. and contributors # For license information, please see license.txt -from __future__ import unicode_literals from frappe.model.document import Document diff --git a/erpnext/restaurant/doctype/restaurant/restaurant_dashboard.py b/erpnext/restaurant/doctype/restaurant/restaurant_dashboard.py index 5b78bb2f45a..bfdd052753e 100644 --- a/erpnext/restaurant/doctype/restaurant/restaurant_dashboard.py +++ b/erpnext/restaurant/doctype/restaurant/restaurant_dashboard.py @@ -1,5 +1,3 @@ -from __future__ import unicode_literals - from frappe import _ diff --git a/erpnext/restaurant/doctype/restaurant/test_restaurant.py b/erpnext/restaurant/doctype/restaurant/test_restaurant.py index 574cd1f9e4a..f88f9801290 100644 --- a/erpnext/restaurant/doctype/restaurant/test_restaurant.py +++ b/erpnext/restaurant/doctype/restaurant/test_restaurant.py @@ -1,7 +1,5 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2017, Frappe Technologies Pvt. Ltd. and Contributors # See license.txt -from __future__ import unicode_literals import unittest diff --git a/erpnext/restaurant/doctype/restaurant_menu/restaurant_menu.py b/erpnext/restaurant/doctype/restaurant_menu/restaurant_menu.py index 632f4850d8a..64eb40f3645 100644 --- a/erpnext/restaurant/doctype/restaurant_menu/restaurant_menu.py +++ b/erpnext/restaurant/doctype/restaurant_menu/restaurant_menu.py @@ -1,8 +1,6 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2017, Frappe Technologies Pvt. Ltd. and contributors # For license information, please see license.txt -from __future__ import unicode_literals import frappe from frappe.model.document import Document diff --git a/erpnext/restaurant/doctype/restaurant_menu/test_restaurant_menu.py b/erpnext/restaurant/doctype/restaurant_menu/test_restaurant_menu.py index 00cbf358d6f..27020eb869f 100644 --- a/erpnext/restaurant/doctype/restaurant_menu/test_restaurant_menu.py +++ b/erpnext/restaurant/doctype/restaurant_menu/test_restaurant_menu.py @@ -1,7 +1,5 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2017, Frappe Technologies Pvt. Ltd. and Contributors # See license.txt -from __future__ import unicode_literals import unittest diff --git a/erpnext/restaurant/doctype/restaurant_menu_item/restaurant_menu_item.py b/erpnext/restaurant/doctype/restaurant_menu_item/restaurant_menu_item.py index 5d095f49a8e..98b245edece 100644 --- a/erpnext/restaurant/doctype/restaurant_menu_item/restaurant_menu_item.py +++ b/erpnext/restaurant/doctype/restaurant_menu_item/restaurant_menu_item.py @@ -1,8 +1,6 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2017, Frappe Technologies Pvt. Ltd. and contributors # For license information, please see license.txt -from __future__ import unicode_literals from frappe.model.document import Document diff --git a/erpnext/restaurant/doctype/restaurant_order_entry/restaurant_order_entry.py b/erpnext/restaurant/doctype/restaurant_order_entry/restaurant_order_entry.py index 1ed5921f350..f9e75b47a0f 100644 --- a/erpnext/restaurant/doctype/restaurant_order_entry/restaurant_order_entry.py +++ b/erpnext/restaurant/doctype/restaurant_order_entry/restaurant_order_entry.py @@ -1,8 +1,6 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2017, Frappe Technologies Pvt. Ltd. and contributors # For license information, please see license.txt -from __future__ import unicode_literals import json diff --git a/erpnext/restaurant/doctype/restaurant_order_entry_item/restaurant_order_entry_item.py b/erpnext/restaurant/doctype/restaurant_order_entry_item/restaurant_order_entry_item.py index ee8928b13a1..0d9c236c0ea 100644 --- a/erpnext/restaurant/doctype/restaurant_order_entry_item/restaurant_order_entry_item.py +++ b/erpnext/restaurant/doctype/restaurant_order_entry_item/restaurant_order_entry_item.py @@ -1,8 +1,6 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2017, Frappe Technologies Pvt. Ltd. and contributors # For license information, please see license.txt -from __future__ import unicode_literals from frappe.model.document import Document diff --git a/erpnext/restaurant/doctype/restaurant_reservation/restaurant_reservation.py b/erpnext/restaurant/doctype/restaurant_reservation/restaurant_reservation.py index f6d2a7c8cc4..02ffaf6c20b 100644 --- a/erpnext/restaurant/doctype/restaurant_reservation/restaurant_reservation.py +++ b/erpnext/restaurant/doctype/restaurant_reservation/restaurant_reservation.py @@ -1,8 +1,6 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2017, Frappe Technologies Pvt. Ltd. and contributors # For license information, please see license.txt -from __future__ import unicode_literals from datetime import timedelta diff --git a/erpnext/restaurant/doctype/restaurant_reservation/test_restaurant_reservation.py b/erpnext/restaurant/doctype/restaurant_reservation/test_restaurant_reservation.py index 885da724aa0..11a3541bd56 100644 --- a/erpnext/restaurant/doctype/restaurant_reservation/test_restaurant_reservation.py +++ b/erpnext/restaurant/doctype/restaurant_reservation/test_restaurant_reservation.py @@ -1,7 +1,5 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2017, Frappe Technologies Pvt. Ltd. and Contributors # See license.txt -from __future__ import unicode_literals import unittest diff --git a/erpnext/restaurant/doctype/restaurant_table/restaurant_table.py b/erpnext/restaurant/doctype/restaurant_table/restaurant_table.py index 0b5d6352711..29f8a1a12b1 100644 --- a/erpnext/restaurant/doctype/restaurant_table/restaurant_table.py +++ b/erpnext/restaurant/doctype/restaurant_table/restaurant_table.py @@ -1,8 +1,6 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2017, Frappe Technologies Pvt. Ltd. and contributors # For license information, please see license.txt -from __future__ import unicode_literals import re diff --git a/erpnext/restaurant/doctype/restaurant_table/test_restaurant_table.py b/erpnext/restaurant/doctype/restaurant_table/test_restaurant_table.py index 44059aee607..00d14d2bb2a 100644 --- a/erpnext/restaurant/doctype/restaurant_table/test_restaurant_table.py +++ b/erpnext/restaurant/doctype/restaurant_table/test_restaurant_table.py @@ -1,7 +1,5 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2017, Frappe Technologies Pvt. Ltd. and Contributors # See license.txt -from __future__ import unicode_literals import unittest diff --git a/erpnext/selling/doctype/__init__.py b/erpnext/selling/doctype/__init__.py index baffc488252..e69de29bb2d 100644 --- a/erpnext/selling/doctype/__init__.py +++ b/erpnext/selling/doctype/__init__.py @@ -1 +0,0 @@ -from __future__ import unicode_literals diff --git a/erpnext/selling/doctype/customer/__init__.py b/erpnext/selling/doctype/customer/__init__.py index baffc488252..e69de29bb2d 100644 --- a/erpnext/selling/doctype/customer/__init__.py +++ b/erpnext/selling/doctype/customer/__init__.py @@ -1 +0,0 @@ -from __future__ import unicode_literals diff --git a/erpnext/selling/doctype/customer/customer.js b/erpnext/selling/doctype/customer/customer.js index cb00019cf5b..107e4a4759d 100644 --- a/erpnext/selling/doctype/customer/customer.js +++ b/erpnext/selling/doctype/customer/customer.js @@ -116,14 +116,15 @@ frappe.ui.form.on("Customer", { frappe.contacts.render_address_and_contact(frm); // custom buttons - frm.add_custom_button(__('Accounting Ledger'), function() { - frappe.set_route('query-report', 'General Ledger', - {party_type:'Customer', party:frm.doc.name}); - }); - frm.add_custom_button(__('Accounts Receivable'), function() { + frm.add_custom_button(__('Accounts Receivable'), function () { frappe.set_route('query-report', 'Accounts Receivable', {customer:frm.doc.name}); - }); + }, __('View')); + + frm.add_custom_button(__('Accounting Ledger'), function () { + frappe.set_route('query-report', 'General Ledger', + {party_type: 'Customer', party: frm.doc.name}); + }, __('View')); frm.add_custom_button(__('Pricing Rule'), function () { erpnext.utils.make_pricing_rule(frm.doc.doctype, frm.doc.name); @@ -133,6 +134,12 @@ frappe.ui.form.on("Customer", { frm.trigger("get_customer_group_details"); }, __('Actions')); + if (cint(frappe.defaults.get_default("enable_common_party_accounting"))) { + frm.add_custom_button(__('Link with Supplier'), function () { + frm.trigger('show_party_link_dialog'); + }, __('Actions')); + } + // indicator erpnext.utils.set_party_dashboard_indicators(frm); @@ -157,5 +164,42 @@ frappe.ui.form.on("Customer", { } }); + }, + show_party_link_dialog: function(frm) { + const dialog = new frappe.ui.Dialog({ + title: __('Select a Supplier'), + fields: [{ + fieldtype: 'Link', label: __('Supplier'), + options: 'Supplier', fieldname: 'supplier', reqd: 1 + }], + primary_action: function({ supplier }) { + frappe.call({ + method: 'erpnext.accounts.doctype.party_link.party_link.create_party_link', + args: { + primary_role: 'Customer', + primary_party: frm.doc.name, + secondary_party: supplier + }, + freeze: true, + callback: function() { + dialog.hide(); + frappe.msgprint({ + message: __('Successfully linked to Supplier'), + alert: true + }); + }, + error: function() { + dialog.hide(); + frappe.msgprint({ + message: __('Linking to Supplier Failed. Please try again.'), + title: __('Linking Failed'), + indicator: 'red' + }); + } + }); + }, + primary_action_label: __('Create Link') + }); + dialog.show(); } }); diff --git a/erpnext/selling/doctype/customer/customer.json b/erpnext/selling/doctype/customer/customer.json index 5913b849eb7..ae406306170 100644 --- a/erpnext/selling/doctype/customer/customer.json +++ b/erpnext/selling/doctype/customer/customer.json @@ -16,11 +16,9 @@ "customer_name", "gender", "customer_type", - "pan", "tax_withholding_category", "default_bank_account", "lead_name", - "prospect", "opportunity_name", "image", "column_break0", @@ -214,7 +212,8 @@ "fieldtype": "Link", "ignore_user_permissions": 1, "label": "Represents Company", - "options": "Company" + "options": "Company", + "unique": 1 }, { "depends_on": "represents_company", @@ -486,25 +485,12 @@ "fieldtype": "Check", "label": "Allow Sales Invoice Creation Without Delivery Note" }, - { - "fieldname": "pan", - "fieldtype": "Data", - "label": "PAN" - }, { "fieldname": "tax_withholding_category", "fieldtype": "Link", "label": "Tax Withholding Category", "options": "Tax Withholding Category" }, - { - "fieldname": "prospect", - "fieldtype": "Link", - "label": "Prospect", - "no_copy": 1, - "options": "Prospect", - "print_hide": 1 - }, { "fieldname": "opportunity_name", "fieldtype": "Link", @@ -518,12 +504,19 @@ "idx": 363, "image_field": "image", "index_web_pages_for_search": 1, - "links": [], - "modified": "2021-08-25 18:56:09.929905", + "links": [ + { + "group": "Allowed Items", + "link_doctype": "Party Specific Item", + "link_fieldname": "party" + } + ], + "modified": "2021-10-20 22:07:52.485809", "modified_by": "Administrator", "module": "Selling", "name": "Customer", "name_case": "Title Case", + "naming_rule": "By \"Naming Series\" field", "owner": "Administrator", "permissions": [ { diff --git a/erpnext/selling/doctype/customer/customer.py b/erpnext/selling/doctype/customer/customer.py index 4be8139d575..2e2b8b77d39 100644 --- a/erpnext/selling/doctype/customer/customer.py +++ b/erpnext/selling/doctype/customer/customer.py @@ -1,7 +1,6 @@ # Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors # License: GNU General Public License v3. See license.txt -from __future__ import unicode_literals import json @@ -14,7 +13,7 @@ from frappe.contacts.address_and_contact import ( ) from frappe.desk.reportview import build_match_conditions, get_filters_cond from frappe.model.mapper import get_mapped_doc -from frappe.model.naming import set_name_by_naming_series +from frappe.model.naming import set_name_by_naming_series, set_name_from_naming_options from frappe.model.rename_doc import update_linked_doctypes from frappe.utils import cint, cstr, flt, get_formatted_email, today from frappe.utils.user import get_users_with_role @@ -40,8 +39,10 @@ class Customer(TransactionBase): cust_master_name = frappe.defaults.get_global_default('cust_master_name') if cust_master_name == 'Customer Name': self.name = self.get_customer_name() - else: + elif cust_master_name == 'Naming Series': set_name_by_naming_series(self) + else: + self.name = set_name_from_naming_options(frappe.get_meta(self.doctype).autoname, self) def get_customer_name(self): @@ -462,11 +463,14 @@ def get_customer_list(doctype, txt, searchfield, start, page_len, filters=None): def check_credit_limit(customer, company, ignore_outstanding_sales_order=False, extra_amount=0): + credit_limit = get_credit_limit(customer, company) + if not credit_limit: + return + customer_outstanding = get_customer_outstanding(customer, company, ignore_outstanding_sales_order) if extra_amount > 0: customer_outstanding += flt(extra_amount) - credit_limit = get_credit_limit(customer, company) if credit_limit > 0 and flt(customer_outstanding) > credit_limit: msgprint(_("Credit limit has been crossed for customer {0} ({1}/{2})") .format(customer, customer_outstanding, credit_limit)) diff --git a/erpnext/selling/doctype/customer/customer_dashboard.py b/erpnext/selling/doctype/customer/customer_dashboard.py index 532c11b86e4..58394d0acb7 100644 --- a/erpnext/selling/doctype/customer/customer_dashboard.py +++ b/erpnext/selling/doctype/customer/customer_dashboard.py @@ -1,5 +1,3 @@ -from __future__ import unicode_literals - from frappe import _ diff --git a/erpnext/selling/doctype/customer/test_customer.py b/erpnext/selling/doctype/customer/test_customer.py index fd1db8fd526..7d6b74d0665 100644 --- a/erpnext/selling/doctype/customer/test_customer.py +++ b/erpnext/selling/doctype/customer/test_customer.py @@ -1,7 +1,6 @@ # Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors # License: GNU General Public License v3. See license.txt -from __future__ import unicode_literals import unittest @@ -18,7 +17,6 @@ test_ignore = ["Price List"] test_dependencies = ['Payment Term', 'Payment Terms Template'] test_records = frappe.get_test_records('Customer') -from six import iteritems class TestCustomer(unittest.TestCase): @@ -91,7 +89,7 @@ class TestCustomer(unittest.TestCase): details = get_party_details("_Test Customer") - for key, value in iteritems(to_check): + for key, value in to_check.items(): val = details.get(key) if not val and not isinstance(val, list): val = None diff --git a/erpnext/selling/doctype/customer_credit_limit/customer_credit_limit.py b/erpnext/selling/doctype/customer_credit_limit/customer_credit_limit.py index 53bcc1b102e..193027b89a4 100644 --- a/erpnext/selling/doctype/customer_credit_limit/customer_credit_limit.py +++ b/erpnext/selling/doctype/customer_credit_limit/customer_credit_limit.py @@ -1,8 +1,6 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2019, Frappe Technologies Pvt. Ltd. and contributors # For license information, please see license.txt -from __future__ import unicode_literals # import frappe from frappe.model.document import Document diff --git a/erpnext/selling/doctype/industry_type/__init__.py b/erpnext/selling/doctype/industry_type/__init__.py index baffc488252..e69de29bb2d 100644 --- a/erpnext/selling/doctype/industry_type/__init__.py +++ b/erpnext/selling/doctype/industry_type/__init__.py @@ -1 +0,0 @@ -from __future__ import unicode_literals diff --git a/erpnext/selling/doctype/industry_type/industry_type.py b/erpnext/selling/doctype/industry_type/industry_type.py index 6d413ece2e7..fbe0131dd31 100644 --- a/erpnext/selling/doctype/industry_type/industry_type.py +++ b/erpnext/selling/doctype/industry_type/industry_type.py @@ -1,7 +1,6 @@ # Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors # License: GNU General Public License v3. See license.txt -from __future__ import unicode_literals from frappe.model.document import Document diff --git a/erpnext/selling/doctype/industry_type/test_industry_type.py b/erpnext/selling/doctype/industry_type/test_industry_type.py index d6cf79ba89b..250c2bec485 100644 --- a/erpnext/selling/doctype/industry_type/test_industry_type.py +++ b/erpnext/selling/doctype/industry_type/test_industry_type.py @@ -1,6 +1,5 @@ # Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors # License: GNU General Public License v3. See license.txt -from __future__ import unicode_literals import frappe diff --git a/erpnext/selling/doctype/installation_note/__init__.py b/erpnext/selling/doctype/installation_note/__init__.py index baffc488252..e69de29bb2d 100644 --- a/erpnext/selling/doctype/installation_note/__init__.py +++ b/erpnext/selling/doctype/installation_note/__init__.py @@ -1 +0,0 @@ -from __future__ import unicode_literals diff --git a/erpnext/selling/doctype/installation_note/installation_note.py b/erpnext/selling/doctype/installation_note/installation_note.py index 128a9415c87..36acdbea612 100644 --- a/erpnext/selling/doctype/installation_note/installation_note.py +++ b/erpnext/selling/doctype/installation_note/installation_note.py @@ -1,7 +1,6 @@ # Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors # License: GNU General Public License v3. See license.txt -from __future__ import unicode_literals import frappe from frappe import _ diff --git a/erpnext/selling/doctype/installation_note/test_installation_note.py b/erpnext/selling/doctype/installation_note/test_installation_note.py index abfda9cd6b8..d3c8be53574 100644 --- a/erpnext/selling/doctype/installation_note/test_installation_note.py +++ b/erpnext/selling/doctype/installation_note/test_installation_note.py @@ -1,7 +1,5 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors # See license.txt -from __future__ import unicode_literals import unittest diff --git a/erpnext/selling/doctype/installation_note_item/__init__.py b/erpnext/selling/doctype/installation_note_item/__init__.py index baffc488252..e69de29bb2d 100644 --- a/erpnext/selling/doctype/installation_note_item/__init__.py +++ b/erpnext/selling/doctype/installation_note_item/__init__.py @@ -1 +0,0 @@ -from __future__ import unicode_literals diff --git a/erpnext/selling/doctype/installation_note_item/installation_note_item.py b/erpnext/selling/doctype/installation_note_item/installation_note_item.py index 862c2a1bb51..2169a7b6144 100644 --- a/erpnext/selling/doctype/installation_note_item/installation_note_item.py +++ b/erpnext/selling/doctype/installation_note_item/installation_note_item.py @@ -1,7 +1,6 @@ # Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors # License: GNU General Public License v3. See license.txt -from __future__ import unicode_literals from frappe.model.document import Document diff --git a/erpnext/healthcare/doctype/healthcare_service_unit/__init__.py b/erpnext/selling/doctype/party_specific_item/__init__.py similarity index 100% rename from erpnext/healthcare/doctype/healthcare_service_unit/__init__.py rename to erpnext/selling/doctype/party_specific_item/__init__.py diff --git a/erpnext/selling/doctype/party_specific_item/party_specific_item.js b/erpnext/selling/doctype/party_specific_item/party_specific_item.js new file mode 100644 index 00000000000..077b93631ec --- /dev/null +++ b/erpnext/selling/doctype/party_specific_item/party_specific_item.js @@ -0,0 +1,8 @@ +// Copyright (c) 2021, Frappe Technologies Pvt. Ltd. and contributors +// For license information, please see license.txt + +frappe.ui.form.on('Party Specific Item', { + // refresh: function(frm) { + + // } +}); diff --git a/erpnext/selling/doctype/party_specific_item/party_specific_item.json b/erpnext/selling/doctype/party_specific_item/party_specific_item.json new file mode 100644 index 00000000000..32b5d478bb5 --- /dev/null +++ b/erpnext/selling/doctype/party_specific_item/party_specific_item.json @@ -0,0 +1,77 @@ +{ + "actions": [], + "creation": "2021-08-27 19:28:07.559978", + "doctype": "DocType", + "editable_grid": 1, + "engine": "InnoDB", + "field_order": [ + "party_type", + "party", + "column_break_3", + "restrict_based_on", + "based_on_value" + ], + "fields": [ + { + "fieldname": "party_type", + "fieldtype": "Select", + "in_list_view": 1, + "label": "Party Type", + "options": "Customer\nSupplier", + "reqd": 1 + }, + { + "fieldname": "party", + "fieldtype": "Dynamic Link", + "in_list_view": 1, + "label": "Party Name", + "options": "party_type", + "reqd": 1 + }, + { + "fieldname": "restrict_based_on", + "fieldtype": "Select", + "in_list_view": 1, + "label": "Restrict Items Based On", + "options": "Item\nItem Group\nBrand", + "reqd": 1 + }, + { + "fieldname": "column_break_3", + "fieldtype": "Column Break" + }, + { + "fieldname": "based_on_value", + "fieldtype": "Dynamic Link", + "in_list_view": 1, + "label": "Based On Value", + "options": "restrict_based_on", + "reqd": 1 + } + ], + "index_web_pages_for_search": 1, + "links": [], + "modified": "2021-09-14 13:27:58.612334", + "modified_by": "Administrator", + "module": "Selling", + "name": "Party Specific Item", + "owner": "Administrator", + "permissions": [ + { + "create": 1, + "delete": 1, + "email": 1, + "export": 1, + "print": 1, + "read": 1, + "report": 1, + "role": "System Manager", + "share": 1, + "write": 1 + } + ], + "sort_field": "modified", + "sort_order": "DESC", + "title_field": "party", + "track_changes": 1 +} \ No newline at end of file diff --git a/erpnext/selling/doctype/party_specific_item/party_specific_item.py b/erpnext/selling/doctype/party_specific_item/party_specific_item.py new file mode 100644 index 00000000000..a408af56420 --- /dev/null +++ b/erpnext/selling/doctype/party_specific_item/party_specific_item.py @@ -0,0 +1,19 @@ +# Copyright (c) 2021, Frappe Technologies Pvt. Ltd. and contributors +# For license information, please see license.txt + +import frappe +from frappe import _ +from frappe.model.document import Document + + +class PartySpecificItem(Document): + def validate(self): + exists = frappe.db.exists({ + 'doctype': 'Party Specific Item', + 'party_type': self.party_type, + 'party': self.party, + 'restrict_based_on': self.restrict_based_on, + 'based_on': self.based_on_value, + }) + if exists: + frappe.throw(_("This item filter has already been applied for the {0}").format(self.party_type)) diff --git a/erpnext/selling/doctype/party_specific_item/test_party_specific_item.py b/erpnext/selling/doctype/party_specific_item/test_party_specific_item.py new file mode 100644 index 00000000000..874a3645929 --- /dev/null +++ b/erpnext/selling/doctype/party_specific_item/test_party_specific_item.py @@ -0,0 +1,38 @@ +# Copyright (c) 2021, Frappe Technologies Pvt. Ltd. and Contributors +# See license.txt + +import unittest + +import frappe + +from erpnext.controllers.queries import item_query + +test_dependencies = ['Item', 'Customer', 'Supplier'] + +def create_party_specific_item(**args): + psi = frappe.new_doc("Party Specific Item") + psi.party_type = args.get('party_type') + psi.party = args.get('party') + psi.restrict_based_on = args.get('restrict_based_on') + psi.based_on_value = args.get('based_on_value') + psi.insert() + +class TestPartySpecificItem(unittest.TestCase): + def setUp(self): + self.customer = frappe.get_last_doc("Customer") + self.supplier = frappe.get_last_doc("Supplier") + self.item = frappe.get_last_doc("Item") + + def test_item_query_for_customer(self): + create_party_specific_item(party_type='Customer', party=self.customer.name, restrict_based_on='Item', based_on_value=self.item.name) + filters = {'is_sales_item': 1, 'customer': self.customer.name} + items = item_query(doctype= 'Item', txt= '', searchfield= 'name', start= 0, page_len= 20,filters=filters, as_dict= False) + for item in items: + self.assertEqual(item[0], self.item.name) + + def test_item_query_for_supplier(self): + create_party_specific_item(party_type='Supplier', party=self.supplier.name, restrict_based_on='Item Group', based_on_value=self.item.item_group) + filters = {'supplier': self.supplier.name, 'is_purchase_item': 1} + items = item_query(doctype= 'Item', txt= '', searchfield= 'name', start= 0, page_len= 20,filters=filters, as_dict= False) + for item in items: + self.assertEqual(item[2], self.item.item_group) diff --git a/erpnext/selling/doctype/product_bundle/product_bundle.py b/erpnext/selling/doctype/product_bundle/product_bundle.py index 4c73916f852..2bb876e6d0f 100644 --- a/erpnext/selling/doctype/product_bundle/product_bundle.py +++ b/erpnext/selling/doctype/product_bundle/product_bundle.py @@ -1,7 +1,6 @@ # Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors # License: GNU General Public License v3. See license.txt -from __future__ import unicode_literals import frappe from frappe import _ diff --git a/erpnext/selling/doctype/product_bundle/test_product_bundle.py b/erpnext/selling/doctype/product_bundle/test_product_bundle.py index 13bd2a30923..c1e2fdee8b8 100644 --- a/erpnext/selling/doctype/product_bundle/test_product_bundle.py +++ b/erpnext/selling/doctype/product_bundle/test_product_bundle.py @@ -1,7 +1,5 @@ - # Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors # License: GNU General Public License v3. See license.txt -from __future__ import unicode_literals import frappe diff --git a/erpnext/selling/doctype/product_bundle_item/product_bundle_item.py b/erpnext/selling/doctype/product_bundle_item/product_bundle_item.py index 5f71a27f369..5c95a555c8f 100644 --- a/erpnext/selling/doctype/product_bundle_item/product_bundle_item.py +++ b/erpnext/selling/doctype/product_bundle_item/product_bundle_item.py @@ -1,8 +1,6 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors and contributors # For license information, please see license.txt -from __future__ import unicode_literals from frappe.model.document import Document diff --git a/erpnext/selling/doctype/quotation/__init__.py b/erpnext/selling/doctype/quotation/__init__.py index baffc488252..e69de29bb2d 100644 --- a/erpnext/selling/doctype/quotation/__init__.py +++ b/erpnext/selling/doctype/quotation/__init__.py @@ -1 +0,0 @@ -from __future__ import unicode_literals diff --git a/erpnext/selling/doctype/quotation/quotation.json b/erpnext/selling/doctype/quotation/quotation.json index 43a44900fcb..ad788e5c8bf 100644 --- a/erpnext/selling/doctype/quotation/quotation.json +++ b/erpnext/selling/doctype/quotation/quotation.json @@ -110,7 +110,8 @@ "enq_det", "supplier_quotation", "opportunity", - "lost_reasons" + "lost_reasons", + "competitors" ], "fields": [ { @@ -946,6 +947,14 @@ "label": "Bundle Items", "options": "fa fa-suitcase", "print_hide": 1 + }, + { + "allow_on_submit": 1, + "fieldname": "competitors", + "fieldtype": "Table MultiSelect", + "label": "Competitors", + "options": "Competitor Detail", + "read_only": 1 } ], "icon": "fa fa-shopping-cart", @@ -953,10 +962,12 @@ "is_submittable": 1, "links": [], "max_attachments": 1, - "modified": "2021-08-27 20:10:07.864951", + "migration_hash": "75a86a19f062c2257bcbc8e6e31c7f1e", + "modified": "2021-10-21 12:58:55.514512", "modified_by": "Administrator", "module": "Selling", "name": "Quotation", + "naming_rule": "By \"Naming Series\" field", "owner": "Administrator", "permissions": [ { diff --git a/erpnext/selling/doctype/quotation/quotation.py b/erpnext/selling/doctype/quotation/quotation.py index 99c43bfc87e..c4752aebb5a 100644 --- a/erpnext/selling/doctype/quotation/quotation.py +++ b/erpnext/selling/doctype/quotation/quotation.py @@ -1,7 +1,6 @@ # Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors # License: GNU General Public License v3. See license.txt -from __future__ import unicode_literals import frappe from frappe import _ @@ -69,7 +68,7 @@ class Quotation(SellingController): opp.set_status(status=status, update=True) @frappe.whitelist() - def declare_enquiry_lost(self, lost_reasons_list, detailed_reason=None): + def declare_enquiry_lost(self, lost_reasons_list, competitors, detailed_reason=None): if not self.has_sales_order(): get_lost_reasons = frappe.get_list('Quotation Lost Reason', fields = ["name"]) @@ -85,6 +84,9 @@ class Quotation(SellingController): else: frappe.throw(_("Invalid lost reason {0}, please create a new lost reason").format(frappe.bold(reason.get('lost_reason')))) + for competitor in competitors: + self.append('competitors', competitor) + self.update_opportunity('Lost') self.update_lead() self.save() diff --git a/erpnext/selling/doctype/quotation/quotation_dashboard.py b/erpnext/selling/doctype/quotation/quotation_dashboard.py index 9586cb10b59..0a1aad7bb6e 100644 --- a/erpnext/selling/doctype/quotation/quotation_dashboard.py +++ b/erpnext/selling/doctype/quotation/quotation_dashboard.py @@ -1,5 +1,3 @@ -from __future__ import unicode_literals - from frappe import _ diff --git a/erpnext/selling/doctype/quotation/test_quotation.py b/erpnext/selling/doctype/quotation/test_quotation.py index a44089a9ce4..769e0661b12 100644 --- a/erpnext/selling/doctype/quotation/test_quotation.py +++ b/erpnext/selling/doctype/quotation/test_quotation.py @@ -1,6 +1,5 @@ # Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors # License: GNU General Public License v3. See license.txt -from __future__ import unicode_literals import unittest diff --git a/erpnext/selling/doctype/quotation_item/__init__.py b/erpnext/selling/doctype/quotation_item/__init__.py index baffc488252..e69de29bb2d 100644 --- a/erpnext/selling/doctype/quotation_item/__init__.py +++ b/erpnext/selling/doctype/quotation_item/__init__.py @@ -1 +0,0 @@ -from __future__ import unicode_literals diff --git a/erpnext/selling/doctype/quotation_item/quotation_item.py b/erpnext/selling/doctype/quotation_item/quotation_item.py index ea472497299..8c2aabbf3fa 100644 --- a/erpnext/selling/doctype/quotation_item/quotation_item.py +++ b/erpnext/selling/doctype/quotation_item/quotation_item.py @@ -1,7 +1,6 @@ # Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors # License: GNU General Public License v3. See license.txt -from __future__ import unicode_literals from frappe.model.document import Document diff --git a/erpnext/selling/doctype/sales_order/__init__.py b/erpnext/selling/doctype/sales_order/__init__.py index baffc488252..e69de29bb2d 100644 --- a/erpnext/selling/doctype/sales_order/__init__.py +++ b/erpnext/selling/doctype/sales_order/__init__.py @@ -1 +0,0 @@ -from __future__ import unicode_literals diff --git a/erpnext/selling/doctype/sales_order/sales_order.js b/erpnext/selling/doctype/sales_order/sales_order.js index f6926906b82..79e9e17e414 100644 --- a/erpnext/selling/doctype/sales_order/sales_order.js +++ b/erpnext/selling/doctype/sales_order/sales_order.js @@ -78,6 +78,8 @@ frappe.ui.form.on("Sales Order", { }); erpnext.queries.setup_warehouse_query(frm); + + frm.ignore_doctypes_on_cancel_all = ['Purchase Order']; }, delivery_date: function(frm) { @@ -317,7 +319,7 @@ erpnext.selling.SalesOrderController = class SalesOrderController extends erpnex title: __('Select Items to Manufacture'), fields: fields, primary_action: function() { - var data = d.get_values(); + var data = {items: d.fields_dict.items.grid.get_selected_children()}; me.frm.call({ method: 'make_work_orders', args: { diff --git a/erpnext/selling/doctype/sales_order/sales_order.json b/erpnext/selling/doctype/sales_order/sales_order.json index 85282ca1a07..7c7ed9a9604 100644 --- a/erpnext/selling/doctype/sales_order/sales_order.json +++ b/erpnext/selling/doctype/sales_order/sales_order.json @@ -1480,6 +1480,7 @@ "fetch_from": "customer.represents_company", "fieldname": "represents_company", "fieldtype": "Link", + "ignore_user_permissions": 1, "label": "Represents Company", "options": "Company", "read_only": 1 @@ -1512,7 +1513,7 @@ "idx": 105, "is_submittable": 1, "links": [], - "modified": "2021-09-01 15:12:24.115483", + "modified": "2021-09-28 13:09:51.515542", "modified_by": "Administrator", "module": "Selling", "name": "Sales Order", diff --git a/erpnext/selling/doctype/sales_order/sales_order.py b/erpnext/selling/doctype/sales_order/sales_order.py index 93676094218..47b8ebd3485 100755 --- a/erpnext/selling/doctype/sales_order/sales_order.py +++ b/erpnext/selling/doctype/sales_order/sales_order.py @@ -1,7 +1,6 @@ # Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors # License: GNU General Public License v3. See license.txt -from __future__ import unicode_literals import json @@ -13,7 +12,6 @@ from frappe.desk.notifications import clear_doctype_notifications from frappe.model.mapper import get_mapped_doc from frappe.model.utils import get_fetch_values from frappe.utils import add_days, cint, cstr, flt, get_link_to_form, getdate, nowdate, strip_html -from six import string_types from erpnext.accounts.doctype.sales_invoice.sales_invoice import ( unlink_inter_company_doc, @@ -110,7 +108,7 @@ class SalesOrder(SellingController): if self.order_type == 'Sales' and not self.skip_delivery_note: delivery_date_list = [d.delivery_date for d in self.get("items") if d.delivery_date] max_delivery_date = max(delivery_date_list) if delivery_date_list else None - if not self.delivery_date: + if (max_delivery_date and not self.delivery_date) or (max_delivery_date and getdate(self.delivery_date) != getdate(max_delivery_date)): self.delivery_date = max_delivery_date if self.delivery_date: for d in self.get("items"): @@ -119,8 +117,6 @@ class SalesOrder(SellingController): if getdate(self.transaction_date) > getdate(d.delivery_date): frappe.msgprint(_("Expected Delivery Date should be after Sales Order Date"), indicator='orange', title=_('Warning')) - if getdate(self.delivery_date) != getdate(max_delivery_date): - self.delivery_date = max_delivery_date else: frappe.throw(_("Please enter Delivery Date")) @@ -227,60 +223,15 @@ class SalesOrder(SellingController): check_credit_limit(self.customer, self.company) def check_nextdoc_docstatus(self): - # Checks Delivery Note - submit_dn = frappe.db.sql_list(""" - select t1.name - from `tabDelivery Note` t1,`tabDelivery Note Item` t2 - where t1.name = t2.parent and t2.against_sales_order = %s and t1.docstatus = 1""", self.name) - - if submit_dn: - submit_dn = [get_link_to_form("Delivery Note", dn) for dn in submit_dn] - frappe.throw(_("Delivery Notes {0} must be cancelled before cancelling this Sales Order") - .format(", ".join(submit_dn))) - - # Checks Sales Invoice - submit_rv = frappe.db.sql_list("""select t1.name + linked_invoices = frappe.db.sql_list("""select distinct t1.name from `tabSales Invoice` t1,`tabSales Invoice Item` t2 - where t1.name = t2.parent and t2.sales_order = %s and t1.docstatus < 2""", + where t1.name = t2.parent and t2.sales_order = %s and t1.docstatus = 0""", self.name) - if submit_rv: - submit_rv = [get_link_to_form("Sales Invoice", si) for si in submit_rv] - frappe.throw(_("Sales Invoice {0} must be cancelled before cancelling this Sales Order") - .format(", ".join(submit_rv))) - - #check maintenance schedule - submit_ms = frappe.db.sql_list(""" - select t1.name - from `tabMaintenance Schedule` t1, `tabMaintenance Schedule Item` t2 - where t2.parent=t1.name and t2.sales_order = %s and t1.docstatus = 1""", self.name) - - if submit_ms: - submit_ms = [get_link_to_form("Maintenance Schedule", ms) for ms in submit_ms] - frappe.throw(_("Maintenance Schedule {0} must be cancelled before cancelling this Sales Order") - .format(", ".join(submit_ms))) - - # check maintenance visit - submit_mv = frappe.db.sql_list(""" - select t1.name - from `tabMaintenance Visit` t1, `tabMaintenance Visit Purpose` t2 - where t2.parent=t1.name and t2.prevdoc_docname = %s and t1.docstatus = 1""",self.name) - - if submit_mv: - submit_mv = [get_link_to_form("Maintenance Visit", mv) for mv in submit_mv] - frappe.throw(_("Maintenance Visit {0} must be cancelled before cancelling this Sales Order") - .format(", ".join(submit_mv))) - - # check work order - pro_order = frappe.db.sql_list(""" - select name - from `tabWork Order` - where sales_order = %s and docstatus = 1""", self.name) - - if pro_order: - pro_order = [get_link_to_form("Work Order", po) for po in pro_order] - frappe.throw(_("Work Order {0} must be cancelled before cancelling this Sales Order") - .format(", ".join(pro_order))) + if linked_invoices: + linked_invoices = [get_link_to_form("Sales Invoice", si) for si in linked_invoices] + frappe.throw(_("Sales Invoice {0} must be deleted before cancelling this Sales Order") + .format(", ".join(linked_invoices))) def check_modified_date(self): mod_db = frappe.db.get_value("Sales Order", self.name, "modified") @@ -793,7 +744,7 @@ def make_purchase_order_for_default_supplier(source_name, selected_items=None, t """Creates Purchase Order for each Supplier. Returns a list of doc objects.""" if not selected_items: return - if isinstance(selected_items, string_types): + if isinstance(selected_items, str): selected_items = json.loads(selected_items) def set_missing_values(source, target): @@ -894,7 +845,7 @@ def make_purchase_order_for_default_supplier(source_name, selected_items=None, t def make_purchase_order(source_name, selected_items=None, target_doc=None): if not selected_items: return - if isinstance(selected_items, string_types): + if isinstance(selected_items, str): selected_items = json.loads(selected_items) items_to_map = [item.get('item_code') for item in selected_items if item.get('item_code') and item.get('item_code')] @@ -1048,7 +999,7 @@ def make_raw_material_request(items, company, sales_order, project=None): if not frappe.has_permission("Sales Order", "write"): frappe.throw(_("Not permitted"), frappe.PermissionError) - if isinstance(items, string_types): + if isinstance(items, str): items = frappe._dict(json.loads(items)) for item in items.get('items'): diff --git a/erpnext/selling/doctype/sales_order/sales_order_dashboard.py b/erpnext/selling/doctype/sales_order/sales_order_dashboard.py index ee3c707b5b8..1e616b87b22 100644 --- a/erpnext/selling/doctype/sales_order/sales_order_dashboard.py +++ b/erpnext/selling/doctype/sales_order/sales_order_dashboard.py @@ -1,5 +1,3 @@ -from __future__ import unicode_literals - from frappe import _ diff --git a/erpnext/selling/doctype/sales_order/test_sales_order.py b/erpnext/selling/doctype/sales_order/test_sales_order.py index bbfe7c06d87..2a0752e56aa 100644 --- a/erpnext/selling/doctype/sales_order/test_sales_order.py +++ b/erpnext/selling/doctype/sales_order/test_sales_order.py @@ -1,6 +1,5 @@ # Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors # License: GNU General Public License v3. See license.txt -from __future__ import unicode_literals import json import unittest @@ -11,6 +10,12 @@ from frappe.core.doctype.user_permission.test_user_permission import create_user from frappe.utils import add_days, flt, getdate, nowdate from erpnext.controllers.accounts_controller import update_child_qty_rate +from erpnext.maintenance.doctype.maintenance_schedule.test_maintenance_schedule import ( + make_maintenance_schedule, +) +from erpnext.maintenance.doctype.maintenance_visit.test_maintenance_visit import ( + make_maintenance_visit, +) from erpnext.manufacturing.doctype.blanket_order.test_blanket_order import make_blanket_order from erpnext.selling.doctype.product_bundle.test_product_bundle import make_product_bundle from erpnext.selling.doctype.sales_order.sales_order import ( @@ -1279,6 +1284,72 @@ class TestSalesOrder(unittest.TestCase): self.assertRaises(frappe.ValidationError, so.cancel) + def test_so_cancellation_after_si_submission(self): + """ + Test to check if Sales Order gets cancelled when linked Sales Invoice has been Submitted + Expected result: Sales Order should not get cancelled + """ + so = make_sales_order() + so.submit() + si = make_sales_invoice(so.name) + si.submit() + + so.load_from_db() + self.assertRaises(frappe.LinkExistsError, so.cancel) + + def test_so_cancellation_after_dn_submission(self): + """ + Test to check if Sales Order gets cancelled when linked Delivery Note has been Submitted + Expected result: Sales Order should not get cancelled + """ + so = make_sales_order() + so.submit() + dn = make_delivery_note(so.name) + dn.submit() + + so.load_from_db() + self.assertRaises(frappe.LinkExistsError, so.cancel) + + def test_so_cancellation_after_maintenance_schedule_submission(self): + """ + Expected result: Sales Order should not get cancelled + """ + so = make_sales_order() + so.submit() + ms = make_maintenance_schedule() + ms.items[0].sales_order = so.name + ms.submit() + + so.load_from_db() + self.assertRaises(frappe.LinkExistsError, so.cancel) + + def test_so_cancellation_after_maintenance_visit_submission(self): + """ + Expected result: Sales Order should not get cancelled + """ + so = make_sales_order() + so.submit() + mv = make_maintenance_visit() + mv.purposes[0].prevdoc_doctype = "Sales Order" + mv.purposes[0].prevdoc_docname = so.name + mv.submit() + + so.load_from_db() + self.assertRaises(frappe.LinkExistsError, so.cancel) + + def test_so_cancellation_after_work_order_submission(self): + """ + Expected result: Sales Order should not get cancelled + """ + from erpnext.manufacturing.doctype.work_order.test_work_order import make_wo_order_test_record + + so = make_sales_order(item_code="_Test FG Item", qty=10) + so.submit() + make_wo_order_test_record(sales_order=so.name) + + so.load_from_db() + self.assertRaises(frappe.LinkExistsError, so.cancel) + def test_payment_terms_are_fetched_when_creating_sales_invoice(self): from erpnext.accounts.doctype.payment_entry.test_payment_entry import ( create_payment_terms_template, @@ -1382,7 +1453,6 @@ def make_sales_order_workflow(): frappe.get_doc(dict(doctype='Role', role_name='Test Junior Approver')).insert(ignore_if_duplicate=True) frappe.get_doc(dict(doctype='Role', role_name='Test Approver')).insert(ignore_if_duplicate=True) - frappe.db.commit() frappe.cache().hdel('roles', frappe.session.user) workflow = frappe.get_doc({ diff --git a/erpnext/selling/doctype/sales_order_item/__init__.py b/erpnext/selling/doctype/sales_order_item/__init__.py index baffc488252..e69de29bb2d 100644 --- a/erpnext/selling/doctype/sales_order_item/__init__.py +++ b/erpnext/selling/doctype/sales_order_item/__init__.py @@ -1 +0,0 @@ -from __future__ import unicode_literals diff --git a/erpnext/selling/doctype/sales_order_item/sales_order_item.py b/erpnext/selling/doctype/sales_order_item/sales_order_item.py index 772aa6c8ae5..441a6ac9709 100644 --- a/erpnext/selling/doctype/sales_order_item/sales_order_item.py +++ b/erpnext/selling/doctype/sales_order_item/sales_order_item.py @@ -1,7 +1,6 @@ # Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors # License: GNU General Public License v3. See license.txt -from __future__ import unicode_literals import frappe from frappe.model.document import Document diff --git a/erpnext/selling/doctype/sales_partner_type/sales_partner_type.py b/erpnext/selling/doctype/sales_partner_type/sales_partner_type.py index bdabef2fdbe..0a07073af05 100644 --- a/erpnext/selling/doctype/sales_partner_type/sales_partner_type.py +++ b/erpnext/selling/doctype/sales_partner_type/sales_partner_type.py @@ -1,8 +1,6 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2018, Frappe Technologies Pvt. Ltd. and contributors # For license information, please see license.txt -from __future__ import unicode_literals from frappe.model.document import Document diff --git a/erpnext/selling/doctype/sales_partner_type/test_sales_partner_type.py b/erpnext/selling/doctype/sales_partner_type/test_sales_partner_type.py index 895b0ecf00a..04d40898254 100644 --- a/erpnext/selling/doctype/sales_partner_type/test_sales_partner_type.py +++ b/erpnext/selling/doctype/sales_partner_type/test_sales_partner_type.py @@ -1,7 +1,5 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2018, Frappe Technologies Pvt. Ltd. and Contributors # See license.txt -from __future__ import unicode_literals import unittest diff --git a/erpnext/selling/doctype/sales_team/__init__.py b/erpnext/selling/doctype/sales_team/__init__.py index baffc488252..e69de29bb2d 100644 --- a/erpnext/selling/doctype/sales_team/__init__.py +++ b/erpnext/selling/doctype/sales_team/__init__.py @@ -1 +0,0 @@ -from __future__ import unicode_literals diff --git a/erpnext/selling/doctype/sales_team/sales_team.json b/erpnext/selling/doctype/sales_team/sales_team.json index 876789135c8..cac5b763ffd 100644 --- a/erpnext/selling/doctype/sales_team/sales_team.json +++ b/erpnext/selling/doctype/sales_team/sales_team.json @@ -1,247 +1,100 @@ { - "allow_copy": 0, - "allow_guest_to_view": 0, - "allow_import": 0, - "allow_rename": 0, - "beta": 0, - "creation": "2013-04-19 13:30:51", - "custom": 0, - "docstatus": 0, - "doctype": "DocType", - "document_type": "Setup", - "editable_grid": 1, - "engine": "InnoDB", + "actions": [], + "creation": "2013-04-19 13:30:51", + "doctype": "DocType", + "document_type": "Setup", + "editable_grid": 1, + "engine": "InnoDB", + "field_order": [ + "sales_person", + "contact_no", + "allocated_percentage", + "allocated_amount", + "commission_rate", + "incentives" + ], "fields": [ { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 1, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "sales_person", - "fieldtype": "Link", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 1, - "in_standard_filter": 0, - "label": "Sales Person", - "length": 0, - "no_copy": 0, - "oldfieldname": "sales_person", - "oldfieldtype": "Link", - "options": "Sales Person", - "permlevel": 0, - "print_hide": 0, - "print_hide_if_no_value": 0, - "print_width": "200px", - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 1, - "search_index": 1, - "set_only_once": 0, - "translatable": 0, - "unique": 0, + "allow_on_submit": 1, + "fieldname": "sales_person", + "fieldtype": "Link", + "in_list_view": 1, + "label": "Sales Person", + "oldfieldname": "sales_person", + "oldfieldtype": "Link", + "options": "Sales Person", + "print_width": "200px", + "reqd": 1, + "search_index": 1, "width": "200px" - }, + }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 1, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "contact_no", - "fieldtype": "Data", - "hidden": 1, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 1, - "in_standard_filter": 0, - "label": "Contact No.", - "length": 0, - "no_copy": 0, - "oldfieldname": "contact_no", - "oldfieldtype": "Data", - "permlevel": 0, - "print_hide": 0, - "print_hide_if_no_value": 0, - "print_width": "100px", - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0, + "allow_on_submit": 1, + "fieldname": "contact_no", + "fieldtype": "Data", + "hidden": 1, + "in_list_view": 1, + "label": "Contact No.", + "oldfieldname": "contact_no", + "oldfieldtype": "Data", + "print_width": "100px", "width": "100px" - }, + }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 1, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "allocated_percentage", - "fieldtype": "Float", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 1, - "in_standard_filter": 0, - "label": "Contribution (%)", - "length": 0, - "no_copy": 0, - "oldfieldname": "allocated_percentage", - "oldfieldtype": "Currency", - "permlevel": 0, - "print_hide": 0, - "print_hide_if_no_value": 0, - "print_width": "100px", - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0, + "allow_on_submit": 1, + "fieldname": "allocated_percentage", + "fieldtype": "Float", + "in_list_view": 1, + "label": "Contribution (%)", + "oldfieldname": "allocated_percentage", + "oldfieldtype": "Currency", + "print_width": "100px", "width": "100px" - }, + }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 1, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "allocated_amount", - "fieldtype": "Currency", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 1, - "in_standard_filter": 0, - "label": "Contribution to Net Total", - "length": 0, - "no_copy": 0, - "oldfieldname": "allocated_amount", - "oldfieldtype": "Currency", - "options": "Company:company:default_currency", - "permlevel": 0, - "print_hide": 0, - "print_hide_if_no_value": 0, - "print_width": "120px", - "read_only": 1, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0, + "allow_on_submit": 1, + "fieldname": "allocated_amount", + "fieldtype": "Currency", + "in_list_view": 1, + "label": "Contribution to Net Total", + "oldfieldname": "allocated_amount", + "oldfieldtype": "Currency", + "options": "Company:company:default_currency", + "print_width": "120px", + "read_only": 1, "width": "120px" - }, + }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "commission_rate", - "fieldtype": "Data", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 1, - "in_standard_filter": 0, - "label": "Commission Rate", - "length": 0, - "no_copy": 0, - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 1, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 - }, + "fetch_from": "sales_person.commission_rate", + "fetch_if_empty": 1, + "fieldname": "commission_rate", + "fieldtype": "Data", + "in_list_view": 1, + "label": "Commission Rate", + "read_only": 1 + }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 1, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "incentives", - "fieldtype": "Currency", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 1, - "in_standard_filter": 0, - "label": "Incentives", - "length": 0, - "no_copy": 0, - "oldfieldname": "incentives", - "oldfieldtype": "Currency", - "options": "Company:company:default_currency", - "permlevel": 0, - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 + "allow_on_submit": 1, + "fieldname": "incentives", + "fieldtype": "Currency", + "in_list_view": 1, + "label": "Incentives", + "oldfieldname": "incentives", + "oldfieldtype": "Currency", + "options": "Company:company:default_currency" } - ], - "has_web_view": 0, - "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": "2018-09-17 13:03:14.755974", - "modified_by": "Administrator", - "module": "Selling", - "name": "Sales Team", - "owner": "Administrator", - "permissions": [], - "quick_entry": 1, - "read_only": 0, - "read_only_onload": 0, - "show_name_in_global_search": 0, - "track_changes": 1, - "track_seen": 0, - "track_views": 0 -} + ], + "idx": 1, + "istable": 1, + "links": [], + "modified": "2021-11-09 23:55:20.670475", + "modified_by": "Administrator", + "module": "Selling", + "name": "Sales Team", + "owner": "Administrator", + "permissions": [], + "quick_entry": 1, + "sort_field": "modified", + "sort_order": "DESC", + "track_changes": 1 +} \ No newline at end of file diff --git a/erpnext/selling/doctype/sales_team/sales_team.py b/erpnext/selling/doctype/sales_team/sales_team.py index 9b542c0eead..d3eae3a5978 100644 --- a/erpnext/selling/doctype/sales_team/sales_team.py +++ b/erpnext/selling/doctype/sales_team/sales_team.py @@ -1,7 +1,6 @@ # Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors # License: GNU General Public License v3. See license.txt -from __future__ import unicode_literals from frappe.model.document import Document diff --git a/erpnext/selling/doctype/selling_settings/selling_settings.json b/erpnext/selling/doctype/selling_settings/selling_settings.json index 59fcb982819..c27f1ea81ad 100644 --- a/erpnext/selling/doctype/selling_settings/selling_settings.json +++ b/erpnext/selling/doctype/selling_settings/selling_settings.json @@ -41,14 +41,14 @@ "fieldtype": "Select", "in_list_view": 1, "label": "Customer Naming By", - "options": "Customer Name\nNaming Series" + "options": "Customer Name\nNaming Series\nAuto Name" }, { "fieldname": "campaign_naming_by", "fieldtype": "Select", "in_list_view": 1, "label": "Campaign Naming By", - "options": "Campaign Name\nNaming Series" + "options": "Campaign Name\nNaming Series\nAuto Name" }, { "fieldname": "customer_group", @@ -204,7 +204,7 @@ "index_web_pages_for_search": 1, "issingle": 1, "links": [], - "modified": "2021-09-01 22:55:33.803624", + "modified": "2021-09-08 19:38:10.175989", "modified_by": "Administrator", "module": "Selling", "name": "Selling Settings", @@ -223,4 +223,4 @@ "sort_field": "modified", "sort_order": "DESC", "track_changes": 1 -} +} \ No newline at end of file diff --git a/erpnext/selling/doctype/selling_settings/selling_settings.py b/erpnext/selling/doctype/selling_settings/selling_settings.py index 5bed43e4609..e7c5e769965 100644 --- a/erpnext/selling/doctype/selling_settings/selling_settings.py +++ b/erpnext/selling/doctype/selling_settings/selling_settings.py @@ -3,7 +3,6 @@ # For license information, please see license.txt -from __future__ import unicode_literals import frappe from frappe.custom.doctype.property_setter.property_setter import make_property_setter diff --git a/erpnext/selling/doctype/selling_settings/test_selling_settings.py b/erpnext/selling/doctype/selling_settings/test_selling_settings.py index 572a110cc3e..fc6754a7c59 100644 --- a/erpnext/selling/doctype/selling_settings/test_selling_settings.py +++ b/erpnext/selling/doctype/selling_settings/test_selling_settings.py @@ -1,7 +1,5 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2019, Frappe Technologies Pvt. Ltd. and Contributors # See license.txt -from __future__ import unicode_literals # import frappe import unittest diff --git a/erpnext/selling/doctype/sms_center/__init__.py b/erpnext/selling/doctype/sms_center/__init__.py index baffc488252..e69de29bb2d 100644 --- a/erpnext/selling/doctype/sms_center/__init__.py +++ b/erpnext/selling/doctype/sms_center/__init__.py @@ -1 +0,0 @@ -from __future__ import unicode_literals diff --git a/erpnext/selling/doctype/sms_center/sms_center.py b/erpnext/selling/doctype/sms_center/sms_center.py index 45aee4ea6f0..d192457ee07 100644 --- a/erpnext/selling/doctype/sms_center/sms_center.py +++ b/erpnext/selling/doctype/sms_center/sms_center.py @@ -1,7 +1,6 @@ # Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors # License: GNU General Public License v3. See license.txt -from __future__ import unicode_literals import frappe from frappe import _, msgprint diff --git a/erpnext/selling/page/__init__.py b/erpnext/selling/page/__init__.py index baffc488252..e69de29bb2d 100644 --- a/erpnext/selling/page/__init__.py +++ b/erpnext/selling/page/__init__.py @@ -1 +0,0 @@ -from __future__ import unicode_literals diff --git a/erpnext/selling/page/point_of_sale/point_of_sale.py b/erpnext/selling/page/point_of_sale/point_of_sale.py index b4338c920a9..db5b20e3e19 100644 --- a/erpnext/selling/page/point_of_sale/point_of_sale.py +++ b/erpnext/selling/page/point_of_sale/point_of_sale.py @@ -1,7 +1,6 @@ # Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors # License: GNU General Public License v3. See license.txt -from __future__ import unicode_literals import json diff --git a/erpnext/selling/page/point_of_sale/pos_item_cart.js b/erpnext/selling/page/point_of_sale/pos_item_cart.js index 9d8338e5fed..a5b2d500414 100644 --- a/erpnext/selling/page/point_of_sale/pos_item_cart.js +++ b/erpnext/selling/page/point_of_sale/pos_item_cart.js @@ -49,11 +49,11 @@ erpnext.PointOfSale.ItemCart = class { this.$component.append( `
    -
    Item Cart
    +
    ${__('Item Cart')}
    -
    Item
    -
    Qty
    -
    Amount
    +
    ${__('Item')}
    +
    ${__('Quantity')}
    +
    ${__('Amount')}
    @@ -78,7 +78,7 @@ erpnext.PointOfSale.ItemCart = class { make_no_items_placeholder() { this.$cart_header.css('display', 'none'); this.$cart_items_wrapper.html( - `
    No items in cart
    ` + `
    ${__('No items in cart')}
    ` ); } @@ -98,19 +98,19 @@ erpnext.PointOfSale.ItemCart = class { this.$totals_section.append( `
    - ${this.get_discount_icon()} Add Discount + ${this.get_discount_icon()} ${__('Add Discount')}
    -
    Net Total
    +
    ${__("Net Total")}
    0.00
    -
    Grand Total
    +
    ${__('Grand Total')}
    0.00
    -
    Checkout
    -
    Edit Cart
    ` +
    ${__('Checkout')}
    +
    ${__('Edit Cart')}
    ` ) this.$add_discount_elem = this.$component.find(".add-discount-wrapper"); @@ -126,10 +126,10 @@ erpnext.PointOfSale.ItemCart = class { }, cols: 5, keys: [ - [ 1, 2, 3, 'Quantity' ], - [ 4, 5, 6, 'Discount' ], - [ 7, 8, 9, 'Rate' ], - [ '.', 0, 'Delete', 'Remove' ] + [ 1, 2, 3, __('Quantity') ], + [ 4, 5, 6, __('Discount') ], + [ 7, 8, 9, __('Rate') ], + [ '.', 0, __('Delete'), __('Remove') ] ], css_classes: [ [ '', '', '', 'col-span-2' ], @@ -148,7 +148,7 @@ erpnext.PointOfSale.ItemCart = class { ) this.$numpad_section.append( - `
    Checkout
    ` + `
    ${__('Checkout')}
    ` ) } @@ -386,7 +386,7 @@ erpnext.PointOfSale.ItemCart = class { 'border': '1px dashed var(--gray-500)', 'padding': 'var(--padding-sm) var(--padding-md)' }); - me.$add_discount_elem.html(`${me.get_discount_icon()} Add Discount`); + me.$add_discount_elem.html(`${me.get_discount_icon()} ${__('Add Discount')}`); me.discount_field = undefined; } }, @@ -411,7 +411,7 @@ erpnext.PointOfSale.ItemCart = class { }); this.$add_discount_elem.html( `
    - ${this.get_discount_icon()} Additional ${String(discount).bold()}% discount applied + ${this.get_discount_icon()} ${__("Additional")} ${String(discount).bold()}% ${__("discount applied")}
    ` ); } @@ -445,7 +445,7 @@ erpnext.PointOfSale.ItemCart = class { function get_customer_description() { if (!email_id && !mobile_no) { - return `
    Click to add email / phone
    `; + return `
    ${__('Click to add email / phone')}
    `; } else if (email_id && !mobile_no) { return `
    ${email_id}
    `; } else if (mobile_no && !email_id) { @@ -479,22 +479,22 @@ erpnext.PointOfSale.ItemCart = class { render_net_total(value) { const currency = this.events.get_frm().doc.currency; this.$totals_section.find('.net-total-container').html( - `
    Net Total
    ${format_currency(value, currency)}
    ` + `
    ${__('Net Total')}
    ${format_currency(value, currency)}
    ` ) this.$numpad_section.find('.numpad-net-total').html( - `
    Net Total: ${format_currency(value, currency)}
    ` + `
    ${__('Net Total')}: ${format_currency(value, currency)}
    ` ); } render_grand_total(value) { const currency = this.events.get_frm().doc.currency; this.$totals_section.find('.grand-total-container').html( - `
    Grand Total
    ${format_currency(value, currency)}
    ` + `
    ${__('Grand Total')}
    ${format_currency(value, currency)}
    ` ) this.$numpad_section.find('.numpad-grand-total').html( - `
    Grand Total: ${format_currency(value, currency)}
    ` + `
    ${__('Grand Total')}: ${format_currency(value, currency)}
    ` ); } @@ -502,6 +502,7 @@ erpnext.PointOfSale.ItemCart = class { if (taxes.length) { const currency = this.events.get_frm().doc.currency; const taxes_html = taxes.map(t => { + if (t.tax_amount_after_discount_amount == 0.0) return; const description = /[0-9]+/.test(t.description) ? t.description : `${t.description} @ ${t.rate}%`; return `
    ${description}
    diff --git a/erpnext/selling/page/point_of_sale/pos_item_details.js b/erpnext/selling/page/point_of_sale/pos_item_details.js index d899c5c19b4..fb69b63f82a 100644 --- a/erpnext/selling/page/point_of_sale/pos_item_details.js +++ b/erpnext/selling/page/point_of_sale/pos_item_details.js @@ -28,7 +28,7 @@ erpnext.PointOfSale.ItemDetails = class { init_child_components() { this.$component.html( `
    -
    Item Details
    +
    ${__('Item Details')}
    @@ -201,8 +201,9 @@ erpnext.PointOfSale.ItemDetails = class { `
    ` ); } + const label = __('Auto Fetch Serial Numbers'); this.$form_container.append( - `
    Auto Fetch Serial Numbers
    ` + `
    ${label}
    ` ); this.$form_container.find('.serial_no-control').find('textarea').css('height', '6rem'); } @@ -236,7 +237,7 @@ erpnext.PointOfSale.ItemDetails = class { if (this.value) { me.events.form_updated(me.current_item, 'warehouse', this.value).then(() => { me.item_stock_map = me.events.get_item_stock_map(); - const available_qty = me.item_stock_map[me.item_row.item_code][this.value]; + const available_qty = me.item_stock_map[me.item_row.item_code] && me.item_stock_map[me.item_row.item_code][this.value]; if (available_qty === undefined) { me.events.get_available_stock(me.item_row.item_code, this.value).then(() => { // item stock map is updated now reset warehouse diff --git a/erpnext/selling/page/point_of_sale/pos_item_selector.js b/erpnext/selling/page/point_of_sale/pos_item_selector.js index 8352b148acc..496385248c4 100644 --- a/erpnext/selling/page/point_of_sale/pos_item_selector.js +++ b/erpnext/selling/page/point_of_sale/pos_item_selector.js @@ -24,7 +24,7 @@ erpnext.PointOfSale.ItemSelector = class { this.wrapper.append( `
    -
    All Items
    +
    ${__('All Items')}
    diff --git a/erpnext/selling/page/point_of_sale/pos_past_order_list.js b/erpnext/selling/page/point_of_sale/pos_past_order_list.js index e0993e2e342..a0475c70d0d 100644 --- a/erpnext/selling/page/point_of_sale/pos_past_order_list.js +++ b/erpnext/selling/page/point_of_sale/pos_past_order_list.js @@ -16,7 +16,7 @@ erpnext.PointOfSale.PastOrderList = class { this.wrapper.append( `
    -
    Recent Orders
    +
    ${__('Recent Orders')}
    diff --git a/erpnext/selling/page/point_of_sale/pos_past_order_summary.js b/erpnext/selling/page/point_of_sale/pos_past_order_summary.js index dd9e05a0e6d..eeb8523f19c 100644 --- a/erpnext/selling/page/point_of_sale/pos_past_order_summary.js +++ b/erpnext/selling/page/point_of_sale/pos_past_order_summary.js @@ -17,16 +17,16 @@ erpnext.PointOfSale.PastOrderSummary = class { this.wrapper.append( `
    - Select an invoice to load summary data + ${__('Select an invoice to load summary data')}
    -
    Items
    +
    ${__('Items')}
    -
    Totals
    +
    ${__('Totals')}
    -
    Payments
    +
    ${__('Payments')}
    @@ -82,7 +82,7 @@ erpnext.PointOfSale.PastOrderSummary = class { return `
    ${doc.customer}
    ${this.customer_email}
    -
    Sold by: ${doc.owner}
    +
    ${__('Sold by')}: ${doc.owner}
    @@ -121,7 +121,7 @@ erpnext.PointOfSale.PastOrderSummary = class { get_net_total_html(doc) { return `
    -
    Net Total
    +
    ${__('Net Total')}
    ${format_currency(doc.net_total, doc.currency)}
    `; } @@ -144,14 +144,14 @@ erpnext.PointOfSale.PastOrderSummary = class { get_grand_total_html(doc) { return `
    -
    Grand Total
    +
    ${__('Grand Total')}
    ${format_currency(doc.grand_total, doc.currency)}
    `; } get_payment_html(doc, payment) { return `
    -
    ${payment.mode_of_payment}
    +
    ${__(payment.mode_of_payment)}
    ${format_currency(payment.amount, doc.currency)}
    `; } @@ -285,8 +285,9 @@ erpnext.PointOfSale.PastOrderSummary = class { if (m.condition) { m.visible_btns.forEach(b => { const class_name = b.split(' ')[0].toLowerCase(); + const btn = __(b); this.$summary_btns.append( - `
    ${b}
    ` + `
    ${btn}
    ` ); }); } diff --git a/erpnext/selling/page/point_of_sale/pos_payment.js b/erpnext/selling/page/point_of_sale/pos_payment.js index 8e69851213f..b9b65591dc7 100644 --- a/erpnext/selling/page/point_of_sale/pos_payment.js +++ b/erpnext/selling/page/point_of_sale/pos_payment.js @@ -18,11 +18,11 @@ erpnext.PointOfSale.Payment = class { prepare_dom() { this.wrapper.append( `
    - +
    - +
    @@ -30,7 +30,7 @@ erpnext.PointOfSale.Payment = class {
    -
    Complete Order
    +
    ${__("Complete Order")}
    ` ); this.$component = this.wrapper.find('.payment-container'); @@ -297,6 +297,7 @@ erpnext.PointOfSale.Payment = class { this.render_payment_mode_dom(); this.make_invoice_fields_control(); this.update_totals_section(); + this.focus_on_default_mop(); } edit_cart() { @@ -378,17 +379,24 @@ erpnext.PointOfSale.Payment = class { }); this[`${mode}_control`].toggle_label(false); this[`${mode}_control`].set_value(p.amount); + }); + this.render_loyalty_points_payment_mode(); + + this.attach_cash_shortcuts(doc); + } + + focus_on_default_mop() { + const doc = this.events.get_frm().doc; + const payments = doc.payments; + payments.forEach(p => { + const mode = p.mode_of_payment.replace(/ +/g, "_").toLowerCase(); if (p.default) { setTimeout(() => { this.$payment_modes.find(`.${mode}.mode-of-payment-control`).parent().click(); }, 500); } }); - - this.render_loyalty_points_payment_mode(); - - this.attach_cash_shortcuts(doc); } attach_cash_shortcuts(doc) { @@ -510,12 +518,12 @@ erpnext.PointOfSale.Payment = class { this.$totals.html( `
    -
    Grand Total
    +
    ${__('Grand Total')}
    ${format_currency(grand_total, currency)}
    -
    Paid Amount
    +
    ${__('Paid Amount')}
    ${format_currency(paid_amount, currency)}
    diff --git a/erpnext/selling/page/sales_funnel/sales_funnel.py b/erpnext/selling/page/sales_funnel/sales_funnel.py index 043a3e7f0fa..a75108e4032 100644 --- a/erpnext/selling/page/sales_funnel/sales_funnel.py +++ b/erpnext/selling/page/sales_funnel/sales_funnel.py @@ -1,7 +1,6 @@ # Copyright (c) 2018, Frappe Technologies Pvt. Ltd. and Contributors # License: GNU General Public License v3. See license.txt -from __future__ import unicode_literals import frappe import pandas as pd diff --git a/erpnext/healthcare/doctype/healthcare_service_unit_type/__init__.py b/erpnext/selling/print_format_field_template/__init__.py similarity index 100% rename from erpnext/healthcare/doctype/healthcare_service_unit_type/__init__.py rename to erpnext/selling/print_format_field_template/__init__.py diff --git a/erpnext/healthcare/doctype/healthcare_settings/__init__.py b/erpnext/selling/print_format_field_template/quotation_taxes/__init__.py similarity index 100% rename from erpnext/healthcare/doctype/healthcare_settings/__init__.py rename to erpnext/selling/print_format_field_template/quotation_taxes/__init__.py diff --git a/erpnext/selling/print_format_field_template/quotation_taxes/quotation_taxes.json b/erpnext/selling/print_format_field_template/quotation_taxes/quotation_taxes.json new file mode 100644 index 00000000000..eaa17cedf05 --- /dev/null +++ b/erpnext/selling/print_format_field_template/quotation_taxes/quotation_taxes.json @@ -0,0 +1,16 @@ +{ + "creation": "2021-10-19 15:48:56.416449", + "docstatus": 0, + "doctype": "Print Format Field Template", + "document_type": "Quotation", + "field": "taxes", + "idx": 0, + "modified": "2021-10-19 18:11:33.553722", + "modified_by": "Administrator", + "module": "Selling", + "name": "Quotation Taxes", + "owner": "Administrator", + "standard": 1, + "template": "", + "template_file": "templates/print_formats/includes/taxes_and_charges.html" +} \ No newline at end of file diff --git a/erpnext/healthcare/doctype/inpatient_medication_entry/__init__.py b/erpnext/selling/print_format_field_template/sales_order_taxes/__init__.py similarity index 100% rename from erpnext/healthcare/doctype/inpatient_medication_entry/__init__.py rename to erpnext/selling/print_format_field_template/sales_order_taxes/__init__.py diff --git a/erpnext/selling/print_format_field_template/sales_order_taxes/sales_order_taxes.json b/erpnext/selling/print_format_field_template/sales_order_taxes/sales_order_taxes.json new file mode 100644 index 00000000000..2aacb440ff8 --- /dev/null +++ b/erpnext/selling/print_format_field_template/sales_order_taxes/sales_order_taxes.json @@ -0,0 +1,16 @@ +{ + "creation": "2021-10-19 18:04:24.443076", + "docstatus": 0, + "doctype": "Print Format Field Template", + "document_type": "Sales Order", + "field": "taxes", + "idx": 0, + "modified": "2021-10-19 18:04:24.443076", + "modified_by": "Administrator", + "module": "Selling", + "name": "Sales Order Taxes", + "owner": "Administrator", + "standard": 1, + "template": "", + "template_file": "templates/print_formats/includes/taxes_and_charges.html" +} \ No newline at end of file diff --git a/erpnext/selling/report/address_and_contacts/address_and_contacts.py b/erpnext/selling/report/address_and_contacts/address_and_contacts.py index fea19f9f16d..915f8dc3cfe 100644 --- a/erpnext/selling/report/address_and_contacts/address_and_contacts.py +++ b/erpnext/selling/report/address_and_contacts/address_and_contacts.py @@ -1,11 +1,8 @@ # Copyright (c) 2013, Frappe Technologies Pvt. Ltd. and contributors # For license information, please see license.txt -from __future__ import unicode_literals import frappe -from six import iteritems -from six.moves import range field_map = { "Contact": [ "first_name", "last_name", "phone", "mobile_no", "email_id", "is_primary_contact" ], @@ -67,7 +64,7 @@ def get_party_addresses_and_contact(party_type, party, party_group): party_details = get_party_details(party_type, party_list, "Address", party_details) party_details = get_party_details(party_type, party_list, "Contact", party_details) - for party, details in iteritems(party_details): + for party, details in party_details.items(): addresses = details.get("address", []) contacts = details.get("contact", []) if not any([addresses, contacts]): diff --git a/erpnext/selling/report/available_stock_for_packing_items/available_stock_for_packing_items.py b/erpnext/selling/report/available_stock_for_packing_items/available_stock_for_packing_items.py index c7040bef708..e702a51d0e7 100644 --- a/erpnext/selling/report/available_stock_for_packing_items/available_stock_for_packing_items.py +++ b/erpnext/selling/report/available_stock_for_packing_items/available_stock_for_packing_items.py @@ -1,7 +1,6 @@ # Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors # License: GNU General Public License v3. See license.txt -from __future__ import unicode_literals import frappe from frappe.utils import flt diff --git a/erpnext/selling/report/customer_acquisition_and_loyalty/customer_acquisition_and_loyalty.py b/erpnext/selling/report/customer_acquisition_and_loyalty/customer_acquisition_and_loyalty.py index a29b5c8a627..2426cbb0b55 100644 --- a/erpnext/selling/report/customer_acquisition_and_loyalty/customer_acquisition_and_loyalty.py +++ b/erpnext/selling/report/customer_acquisition_and_loyalty/customer_acquisition_and_loyalty.py @@ -1,7 +1,6 @@ # Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors # License: GNU General Public License v3. See license.txt -from __future__ import unicode_literals import calendar diff --git a/erpnext/selling/report/customer_credit_balance/customer_credit_balance.py b/erpnext/selling/report/customer_credit_balance/customer_credit_balance.py index ed2fbfd595c..777b02ca66d 100644 --- a/erpnext/selling/report/customer_credit_balance/customer_credit_balance.py +++ b/erpnext/selling/report/customer_credit_balance/customer_credit_balance.py @@ -1,7 +1,6 @@ # Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors and contributors # For license information, please see license.txt -from __future__ import unicode_literals import frappe from frappe import _ diff --git a/erpnext/selling/report/customer_wise_item_price/customer_wise_item_price.py b/erpnext/selling/report/customer_wise_item_price/customer_wise_item_price.py index 535d551cfab..e5f93543209 100644 --- a/erpnext/selling/report/customer_wise_item_price/customer_wise_item_price.py +++ b/erpnext/selling/report/customer_wise_item_price/customer_wise_item_price.py @@ -1,7 +1,6 @@ # Copyright (c) 2013, Frappe Technologies Pvt. Ltd. and contributors # For license information, please see license.txt -from __future__ import unicode_literals import frappe from frappe import _ diff --git a/erpnext/selling/report/inactive_customers/inactive_customers.py b/erpnext/selling/report/inactive_customers/inactive_customers.py index c79efe24b78..d97e1c6dcb0 100644 --- a/erpnext/selling/report/inactive_customers/inactive_customers.py +++ b/erpnext/selling/report/inactive_customers/inactive_customers.py @@ -1,7 +1,6 @@ # Copyright (c) 2013, Frappe Technologies Pvt. Ltd. and contributors # For license information, please see license.txt -from __future__ import unicode_literals import frappe from frappe import _ diff --git a/erpnext/selling/report/item_wise_sales_history/item_wise_sales_history.py b/erpnext/selling/report/item_wise_sales_history/item_wise_sales_history.py index 539631240e1..4a245e1f778 100644 --- a/erpnext/selling/report/item_wise_sales_history/item_wise_sales_history.py +++ b/erpnext/selling/report/item_wise_sales_history/item_wise_sales_history.py @@ -1,7 +1,6 @@ # Copyright (c) 2019, Frappe Technologies Pvt. Ltd. and contributors # For license information, please see license.txt -from __future__ import unicode_literals import frappe from frappe import _ diff --git a/erpnext/selling/report/pending_so_items_for_purchase_request/pending_so_items_for_purchase_request.py b/erpnext/selling/report/pending_so_items_for_purchase_request/pending_so_items_for_purchase_request.py index f241a3e13d9..01421e8fd0e 100644 --- a/erpnext/selling/report/pending_so_items_for_purchase_request/pending_so_items_for_purchase_request.py +++ b/erpnext/selling/report/pending_so_items_for_purchase_request/pending_so_items_for_purchase_request.py @@ -1,7 +1,6 @@ # Copyright (c) 2013, Frappe Technologies Pvt. Ltd. and contributors # For license information, please see license.txt -from __future__ import unicode_literals import frappe from frappe import _ diff --git a/erpnext/selling/report/pending_so_items_for_purchase_request/test_pending_so_items_for_purchase_request.py b/erpnext/selling/report/pending_so_items_for_purchase_request/test_pending_so_items_for_purchase_request.py index 95e332ac537..9c30afc5b1a 100644 --- a/erpnext/selling/report/pending_so_items_for_purchase_request/test_pending_so_items_for_purchase_request.py +++ b/erpnext/selling/report/pending_so_items_for_purchase_request/test_pending_so_items_for_purchase_request.py @@ -1,7 +1,6 @@ # Copyright (c) 2013, Frappe Technologies Pvt. Ltd. and contributors # For license information, please see license.txt -from __future__ import unicode_literals import unittest diff --git a/erpnext/selling/report/quotation_trends/quotation_trends.py b/erpnext/selling/report/quotation_trends/quotation_trends.py index d2ee9a8b742..047b09081af 100644 --- a/erpnext/selling/report/quotation_trends/quotation_trends.py +++ b/erpnext/selling/report/quotation_trends/quotation_trends.py @@ -1,7 +1,6 @@ # Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors # License: GNU General Public License v3. See license.txt -from __future__ import unicode_literals from frappe import _ diff --git a/erpnext/selling/report/sales_analytics/sales_analytics.py b/erpnext/selling/report/sales_analytics/sales_analytics.py index 56bcb3180a3..83588c34569 100644 --- a/erpnext/selling/report/sales_analytics/sales_analytics.py +++ b/erpnext/selling/report/sales_analytics/sales_analytics.py @@ -1,12 +1,10 @@ # Copyright (c) 2013, Frappe Technologies Pvt. Ltd. and contributors # For license information, please see license.txt -from __future__ import unicode_literals import frappe from frappe import _, scrub from frappe.utils import add_days, add_to_date, flt, getdate -from six import iteritems from erpnext.accounts.utils import get_fiscal_year @@ -227,7 +225,7 @@ class Analytics(object): self.data = [] self.get_periodic_data() - for entity, period_data in iteritems(self.entity_periodic_data): + for entity, period_data in self.entity_periodic_data.items(): row = { "entity": entity, "entity_name": self.entity_names.get(entity) if hasattr(self, 'entity_names') else None diff --git a/erpnext/selling/report/sales_analytics/test_analytics.py b/erpnext/selling/report/sales_analytics/test_analytics.py index a1800993f4f..8ffc5d6d0a7 100644 --- a/erpnext/selling/report/sales_analytics/test_analytics.py +++ b/erpnext/selling/report/sales_analytics/test_analytics.py @@ -1,7 +1,6 @@ # Copyright (c) 2013, Frappe Technologies Pvt. Ltd. and contributors # For license information, please see license.txt -from __future__ import unicode_literals import unittest diff --git a/erpnext/selling/report/sales_order_analysis/sales_order_analysis.py b/erpnext/selling/report/sales_order_analysis/sales_order_analysis.py index 805c3d804fa..82e5d0ce57d 100644 --- a/erpnext/selling/report/sales_order_analysis/sales_order_analysis.py +++ b/erpnext/selling/report/sales_order_analysis/sales_order_analysis.py @@ -1,7 +1,6 @@ # Copyright (c) 2013, Frappe Technologies Pvt. Ltd. and contributors # For license information, please see license.txt -from __future__ import unicode_literals import copy @@ -73,7 +72,7 @@ def get_data(conditions, filters): `tabSales Order` so, `tabSales Order Item` soi LEFT JOIN `tabSales Invoice Item` sii - ON sii.so_detail = soi.name + ON sii.so_detail = soi.name and sii.docstatus = 1 WHERE soi.parent = so.name and so.status not in ('Stopped', 'Closed', 'On Hold') diff --git a/erpnext/selling/report/sales_order_trends/sales_order_trends.py b/erpnext/selling/report/sales_order_trends/sales_order_trends.py index 89daf447781..5a711712620 100644 --- a/erpnext/selling/report/sales_order_trends/sales_order_trends.py +++ b/erpnext/selling/report/sales_order_trends/sales_order_trends.py @@ -1,7 +1,6 @@ # Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors # License: GNU General Public License v3. See license.txt -from __future__ import unicode_literals from frappe import _ diff --git a/erpnext/selling/report/sales_partner_commission_summary/sales_partner_commission_summary.py b/erpnext/selling/report/sales_partner_commission_summary/sales_partner_commission_summary.py index a84dec032e5..b775907bd53 100644 --- a/erpnext/selling/report/sales_partner_commission_summary/sales_partner_commission_summary.py +++ b/erpnext/selling/report/sales_partner_commission_summary/sales_partner_commission_summary.py @@ -1,7 +1,6 @@ # Copyright (c) 2013, Frappe Technologies Pvt. Ltd. and contributors # For license information, please see license.txt -from __future__ import unicode_literals import frappe from frappe import _, msgprint diff --git a/erpnext/selling/report/sales_partner_target_variance_based_on_item_group/item_group_wise_sales_target_variance.py b/erpnext/selling/report/sales_partner_target_variance_based_on_item_group/item_group_wise_sales_target_variance.py index d4f49c71464..a647eb4fea2 100644 --- a/erpnext/selling/report/sales_partner_target_variance_based_on_item_group/item_group_wise_sales_target_variance.py +++ b/erpnext/selling/report/sales_partner_target_variance_based_on_item_group/item_group_wise_sales_target_variance.py @@ -1,7 +1,6 @@ # Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors # License: GNU General Public License v3. See license.txt -from __future__ import unicode_literals import frappe from frappe import _ diff --git a/erpnext/selling/report/sales_partner_target_variance_based_on_item_group/sales_partner_target_variance_based_on_item_group.py b/erpnext/selling/report/sales_partner_target_variance_based_on_item_group/sales_partner_target_variance_based_on_item_group.py index de21c4ad02d..f2b6a54a8a6 100644 --- a/erpnext/selling/report/sales_partner_target_variance_based_on_item_group/sales_partner_target_variance_based_on_item_group.py +++ b/erpnext/selling/report/sales_partner_target_variance_based_on_item_group/sales_partner_target_variance_based_on_item_group.py @@ -1,7 +1,6 @@ # Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors # License: GNU General Public License v3. See license.txt -from __future__ import unicode_literals from erpnext.selling.report.sales_partner_target_variance_based_on_item_group.item_group_wise_sales_target_variance import ( get_data_column, diff --git a/erpnext/selling/report/sales_partner_transaction_summary/sales_partner_transaction_summary.py b/erpnext/selling/report/sales_partner_transaction_summary/sales_partner_transaction_summary.py index 39ec072f6ba..c64555bf2d3 100644 --- a/erpnext/selling/report/sales_partner_transaction_summary/sales_partner_transaction_summary.py +++ b/erpnext/selling/report/sales_partner_transaction_summary/sales_partner_transaction_summary.py @@ -1,7 +1,6 @@ # Copyright (c) 2013, Frappe Technologies Pvt. Ltd. and contributors # For license information, please see license.txt -from __future__ import unicode_literals import frappe from frappe import _, msgprint diff --git a/erpnext/selling/report/sales_person_commission_summary/sales_person_commission_summary.py b/erpnext/selling/report/sales_person_commission_summary/sales_person_commission_summary.py index 13245b789ef..1542e31feff 100644 --- a/erpnext/selling/report/sales_person_commission_summary/sales_person_commission_summary.py +++ b/erpnext/selling/report/sales_person_commission_summary/sales_person_commission_summary.py @@ -1,7 +1,6 @@ # Copyright (c) 2013, Frappe Technologies Pvt. Ltd. and contributors # For license information, please see license.txt -from __future__ import unicode_literals import frappe from frappe import _, msgprint diff --git a/erpnext/selling/report/sales_person_target_variance_based_on_item_group/sales_person_target_variance_based_on_item_group.py b/erpnext/selling/report/sales_person_target_variance_based_on_item_group/sales_person_target_variance_based_on_item_group.py index 83a1c2ce75c..dda24662bb2 100644 --- a/erpnext/selling/report/sales_person_target_variance_based_on_item_group/sales_person_target_variance_based_on_item_group.py +++ b/erpnext/selling/report/sales_person_target_variance_based_on_item_group/sales_person_target_variance_based_on_item_group.py @@ -1,7 +1,6 @@ # Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors # License: GNU General Public License v3. See license.txt -from __future__ import unicode_literals from erpnext.selling.report.sales_partner_target_variance_based_on_item_group.item_group_wise_sales_target_variance import ( get_data_column, diff --git a/erpnext/selling/report/sales_person_wise_transaction_summary/sales_person_wise_transaction_summary.py b/erpnext/selling/report/sales_person_wise_transaction_summary/sales_person_wise_transaction_summary.py index 9dc2923b0a2..c621be88295 100644 --- a/erpnext/selling/report/sales_person_wise_transaction_summary/sales_person_wise_transaction_summary.py +++ b/erpnext/selling/report/sales_person_wise_transaction_summary/sales_person_wise_transaction_summary.py @@ -1,7 +1,6 @@ # Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors # License: GNU General Public License v3. See license.txt -from __future__ import unicode_literals import frappe from frappe import _, msgprint diff --git a/erpnext/selling/report/territory_target_variance_based_on_item_group/territory_target_variance_based_on_item_group.py b/erpnext/selling/report/territory_target_variance_based_on_item_group/territory_target_variance_based_on_item_group.py index b340124a040..eee2d42a786 100644 --- a/erpnext/selling/report/territory_target_variance_based_on_item_group/territory_target_variance_based_on_item_group.py +++ b/erpnext/selling/report/territory_target_variance_based_on_item_group/territory_target_variance_based_on_item_group.py @@ -1,7 +1,6 @@ # Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors # License: GNU General Public License v3. See license.txt -from __future__ import unicode_literals from erpnext.selling.report.sales_partner_target_variance_based_on_item_group.item_group_wise_sales_target_variance import ( get_data_column, diff --git a/erpnext/selling/report/territory_wise_sales/territory_wise_sales.py b/erpnext/selling/report/territory_wise_sales/territory_wise_sales.py index c334381b430..b7b4d3aa4ca 100644 --- a/erpnext/selling/report/territory_wise_sales/territory_wise_sales.py +++ b/erpnext/selling/report/territory_wise_sales/territory_wise_sales.py @@ -1,7 +1,6 @@ # Copyright (c) 2013, Frappe Technologies Pvt. Ltd. and contributors # For license information, please see license.txt -from __future__ import unicode_literals import frappe from frappe import _ diff --git a/erpnext/selling/sales_common.js b/erpnext/selling/sales_common.js index 955ef5e9396..20504789aa7 100644 --- a/erpnext/selling/sales_common.js +++ b/erpnext/selling/sales_common.js @@ -63,7 +63,7 @@ erpnext.selling.SellingController = class SellingController extends erpnext.Tran this.frm.set_query("item_code", "items", function() { return { query: "erpnext.controllers.queries.item_query", - filters: {'is_sales_item': 1} + filters: {'is_sales_item': 1, 'customer': cur_frm.doc.customer} } }); } @@ -206,8 +206,10 @@ erpnext.selling.SellingController = class SellingController extends erpnext.Tran var me = this; var item = frappe.get_doc(cdt, cdn); - if (item.serial_no && item.qty === item.serial_no.split(`\n`).length) { - return; + // check if serial nos entered are as much as qty in row + if (item.serial_no) { + let serial_nos = item.serial_no.split(`\n`).filter(sn => sn.trim()); // filter out whitespaces + if (item.qty === serial_nos.length) return; } if (item.serial_no && !item.batch_no) { @@ -247,7 +249,12 @@ erpnext.selling.SellingController = class SellingController extends erpnext.Tran var editable_price_list_rate = cint(frappe.defaults.get_default("editable_price_list_rate")); if(df && editable_price_list_rate) { - df.read_only = 0; + const parent_field = frappe.meta.get_parentfield(this.frm.doc.doctype, this.frm.doc.doctype + " Item"); + if (!this.frm.fields_dict[parent_field]) return; + + this.frm.fields_dict[parent_field].grid.update_docfield_property( + 'price_list_rate', 'read_only', 0 + ); } } @@ -466,6 +473,12 @@ frappe.ui.form.on(cur_frm.doctype, { "options": frm.doctype === 'Opportunity' ? 'Opportunity Lost Reason Detail': 'Quotation Lost Reason Detail', "reqd": 1 }, + { + "fieldtype": "Table MultiSelect", + "label": __("Competitors"), + "fieldname": "competitors", + "options": "Competitor Detail" + }, { "fieldtype": "Text", "label": __("Detailed Reason"), @@ -473,27 +486,25 @@ frappe.ui.form.on(cur_frm.doctype, { }, ], primary_action: function() { - var values = dialog.get_values(); - var reasons = values["lost_reason"]; - var detailed_reason = values["detailed_reason"]; + let values = dialog.get_values(); frm.call({ doc: frm.doc, method: 'declare_enquiry_lost', args: { - 'lost_reasons_list': reasons, - 'detailed_reason': detailed_reason + 'lost_reasons_list': values.lost_reason, + 'competitors': values.competitors, + 'detailed_reason': values.detailed_reason }, callback: function(r) { dialog.hide(); frm.reload_doc(); }, }); - refresh_field("lost_reason"); }, primary_action_label: __('Declare Lost') }); dialog.show(); } -}) +}) \ No newline at end of file diff --git a/erpnext/selling/workspace/retail/retail.json b/erpnext/selling/workspace/retail/retail.json index 9d2e6cabbc3..a851ace738c 100644 --- a/erpnext/selling/workspace/retail/retail.json +++ b/erpnext/selling/workspace/retail/retail.json @@ -1,20 +1,13 @@ { - "category": "", "charts": [], "content": "[{\"type\": \"header\", \"data\": {\"text\": \"Your Shortcuts\", \"level\": 4, \"col\": 12}}, {\"type\": \"shortcut\", \"data\": {\"shortcut_name\": \"Point Of Sale\", \"col\": 4}}, {\"type\": \"spacer\", \"data\": {\"col\": 12}}, {\"type\": \"header\", \"data\": {\"text\": \"Reports & Masters\", \"level\": 4, \"col\": 12}}, {\"type\": \"card\", \"data\": {\"card_name\": \"Settings & Configurations\", \"col\": 4}}, {\"type\": \"card\", \"data\": {\"card_name\": \"Loyalty Program\", \"col\": 4}}, {\"type\": \"card\", \"data\": {\"card_name\": \"Opening & Closing\", \"col\": 4}}]", "creation": "2020-03-02 17:18:32.505616", - "developer_mode_only": 0, - "disable_user_customization": 0, "docstatus": 0, "doctype": "Workspace", - "extends": "", - "extends_another_page": 0, "for_user": "", "hide_custom": 0, "icon": "retail", "idx": 0, - "is_default": 0, - "is_standard": 0, "label": "Retail", "links": [ { @@ -108,15 +101,12 @@ "type": "Link" } ], - "modified": "2021-08-05 12:16:01.840988", + "modified": "2021-08-05 12:16:01.840989", "modified_by": "Administrator", "module": "Selling", "name": "Retail", - "onboarding": "", "owner": "Administrator", "parent_page": "", - "pin_to_bottom": 0, - "pin_to_top": 0, "public": 1, "restrict_to_domain": "Retail", "roles": [], diff --git a/erpnext/selling/workspace/selling/selling.json b/erpnext/selling/workspace/selling/selling.json index 345187f93c4..db2e6bafd55 100644 --- a/erpnext/selling/workspace/selling/selling.json +++ b/erpnext/selling/workspace/selling/selling.json @@ -1,26 +1,18 @@ { - "category": "", "charts": [ { "chart_name": "Sales Order Trends", "label": "Sales Order Trends" } ], - "charts_label": "Selling ", "content": "[{\"type\": \"onboarding\", \"data\": {\"onboarding_name\":\"Selling\", \"col\": 12}}, {\"type\": \"chart\", \"data\": {\"chart_name\": \"Sales Order Trends\", \"col\": 12}}, {\"type\": \"spacer\", \"data\": {\"col\": 12}}, {\"type\": \"header\", \"data\": {\"text\": \"Quick Access\", \"level\": 4, \"col\": 12}}, {\"type\": \"shortcut\", \"data\": {\"shortcut_name\": \"Item\", \"col\": 4}}, {\"type\": \"shortcut\", \"data\": {\"shortcut_name\": \"Sales Order\", \"col\": 4}}, {\"type\": \"shortcut\", \"data\": {\"shortcut_name\": \"Sales Analytics\", \"col\": 4}}, {\"type\": \"shortcut\", \"data\": {\"shortcut_name\": \"Sales Order Analysis\", \"col\": 4}}, {\"type\": \"shortcut\", \"data\": {\"shortcut_name\": \"Dashboard\", \"col\": 4}}, {\"type\": \"spacer\", \"data\": {\"col\": 12}}, {\"type\": \"header\", \"data\": {\"text\": \"Reports & Masters\", \"level\": 4, \"col\": 12}}, {\"type\": \"card\", \"data\": {\"card_name\": \"Selling\", \"col\": 4}}, {\"type\": \"card\", \"data\": {\"card_name\": \"Items and Pricing\", \"col\": 4}}, {\"type\": \"card\", \"data\": {\"card_name\": \"Settings\", \"col\": 4}}, {\"type\": \"card\", \"data\": {\"card_name\": \"Key Reports\", \"col\": 4}}, {\"type\": \"card\", \"data\": {\"card_name\": \"Other Reports\", \"col\": 4}}]", "creation": "2020-01-28 11:49:12.092882", - "developer_mode_only": 0, - "disable_user_customization": 0, "docstatus": 0, "doctype": "Workspace", - "extends": "", - "extends_another_page": 0, "for_user": "", "hide_custom": 0, "icon": "sell", "idx": 0, - "is_default": 0, - "is_standard": 0, "label": "Selling", "links": [ { @@ -570,15 +562,12 @@ "type": "Link" } ], - "modified": "2021-08-05 12:16:01.990702", + "modified": "2021-08-05 12:16:01.990703", "modified_by": "Administrator", "module": "Selling", "name": "Selling", - "onboarding": "Selling", "owner": "Administrator", "parent_page": "", - "pin_to_bottom": 0, - "pin_to_top": 0, "public": 1, "restrict_to_domain": "", "roles": [], @@ -619,6 +608,5 @@ "type": "Dashboard" } ], - "shortcuts_label": "Quick Access", "title": "Selling" } \ No newline at end of file diff --git a/erpnext/setup/default_energy_point_rules.py b/erpnext/setup/default_energy_point_rules.py index c41d000215b..1ce06b8c2f4 100644 --- a/erpnext/setup/default_energy_point_rules.py +++ b/erpnext/setup/default_energy_point_rules.py @@ -1,5 +1,3 @@ -from __future__ import unicode_literals - from frappe import _ doctype_rule_map = { diff --git a/erpnext/setup/default_success_action.py b/erpnext/setup/default_success_action.py index be072fc47f3..a1f48df672a 100644 --- a/erpnext/setup/default_success_action.py +++ b/erpnext/setup/default_success_action.py @@ -1,5 +1,3 @@ -from __future__ import unicode_literals - from frappe import _ doctype_list = [ diff --git a/erpnext/setup/doctype/__init__.py b/erpnext/setup/doctype/__init__.py index baffc488252..e69de29bb2d 100644 --- a/erpnext/setup/doctype/__init__.py +++ b/erpnext/setup/doctype/__init__.py @@ -1 +0,0 @@ -from __future__ import unicode_literals diff --git a/erpnext/setup/doctype/authorization_control/__init__.py b/erpnext/setup/doctype/authorization_control/__init__.py index baffc488252..e69de29bb2d 100644 --- a/erpnext/setup/doctype/authorization_control/__init__.py +++ b/erpnext/setup/doctype/authorization_control/__init__.py @@ -1 +0,0 @@ -from __future__ import unicode_literals diff --git a/erpnext/setup/doctype/authorization_control/authorization_control.py b/erpnext/setup/doctype/authorization_control/authorization_control.py index 332d7f438a7..2a0d785520a 100644 --- a/erpnext/setup/doctype/authorization_control/authorization_control.py +++ b/erpnext/setup/doctype/authorization_control/authorization_control.py @@ -1,7 +1,6 @@ # Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors # License: GNU General Public License v3. See license.txt -from __future__ import unicode_literals import frappe from frappe import _, session diff --git a/erpnext/setup/doctype/authorization_rule/__init__.py b/erpnext/setup/doctype/authorization_rule/__init__.py index baffc488252..e69de29bb2d 100644 --- a/erpnext/setup/doctype/authorization_rule/__init__.py +++ b/erpnext/setup/doctype/authorization_rule/__init__.py @@ -1 +0,0 @@ -from __future__ import unicode_literals diff --git a/erpnext/setup/doctype/authorization_rule/authorization_rule.py b/erpnext/setup/doctype/authorization_rule/authorization_rule.py index ab0f4201219..e07de3b2934 100644 --- a/erpnext/setup/doctype/authorization_rule/authorization_rule.py +++ b/erpnext/setup/doctype/authorization_rule/authorization_rule.py @@ -1,7 +1,6 @@ # Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors # License: GNU General Public License v3. See license.txt -from __future__ import unicode_literals import frappe from frappe import _ diff --git a/erpnext/setup/doctype/authorization_rule/test_authorization_rule.py b/erpnext/setup/doctype/authorization_rule/test_authorization_rule.py index 8a0f6649078..7d3d5d4c4d3 100644 --- a/erpnext/setup/doctype/authorization_rule/test_authorization_rule.py +++ b/erpnext/setup/doctype/authorization_rule/test_authorization_rule.py @@ -1,7 +1,5 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors # See license.txt -from __future__ import unicode_literals import unittest diff --git a/erpnext/setup/doctype/brand/__init__.py b/erpnext/setup/doctype/brand/__init__.py index baffc488252..e69de29bb2d 100644 --- a/erpnext/setup/doctype/brand/__init__.py +++ b/erpnext/setup/doctype/brand/__init__.py @@ -1 +0,0 @@ -from __future__ import unicode_literals diff --git a/erpnext/setup/doctype/brand/brand.py b/erpnext/setup/doctype/brand/brand.py index 4cfb018c865..9b91b456c34 100644 --- a/erpnext/setup/doctype/brand/brand.py +++ b/erpnext/setup/doctype/brand/brand.py @@ -1,7 +1,6 @@ # Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors # License: GNU General Public License v3. See license.txt -from __future__ import unicode_literals import copy diff --git a/erpnext/setup/doctype/brand/test_brand.py b/erpnext/setup/doctype/brand/test_brand.py index 16873c9fc92..1c71448cb8d 100644 --- a/erpnext/setup/doctype/brand/test_brand.py +++ b/erpnext/setup/doctype/brand/test_brand.py @@ -1,6 +1,5 @@ # Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors # License: GNU General Public License v3. See license.txt -from __future__ import unicode_literals import frappe diff --git a/erpnext/setup/doctype/company/__init__.py b/erpnext/setup/doctype/company/__init__.py index baffc488252..e69de29bb2d 100644 --- a/erpnext/setup/doctype/company/__init__.py +++ b/erpnext/setup/doctype/company/__init__.py @@ -1 +0,0 @@ -from __future__ import unicode_literals diff --git a/erpnext/setup/doctype/company/company.js b/erpnext/setup/doctype/company/company.js index 8403193df53..95ca3867ee7 100644 --- a/erpnext/setup/doctype/company/company.js +++ b/erpnext/setup/doctype/company/company.js @@ -46,43 +46,6 @@ frappe.ui.form.on("Company", { }); }, - change_abbreviation(frm) { - var dialog = new frappe.ui.Dialog({ - title: "Replace Abbr", - fields: [ - {"fieldtype": "Data", "label": "New Abbreviation", "fieldname": "new_abbr", - "reqd": 1 }, - {"fieldtype": "Button", "label": "Update", "fieldname": "update"}, - ] - }); - - dialog.fields_dict.update.$input.click(function() { - var args = dialog.get_values(); - if (!args) return; - frappe.show_alert(__("Update in progress. It might take a while.")); - return frappe.call({ - method: "erpnext.setup.doctype.company.company.enqueue_replace_abbr", - args: { - "company": frm.doc.name, - "old": frm.doc.abbr, - "new": args.new_abbr - }, - callback: function(r) { - if (r.exc) { - frappe.msgprint(__("There were errors.")); - return; - } else { - frm.set_value("abbr", args.new_abbr); - } - dialog.hide(); - frm.refresh(); - }, - btn: this - }); - }); - dialog.show(); - }, - company_name: function(frm) { if(frm.doc.__islocal) { // add missing " " arg in split method @@ -164,10 +127,6 @@ frappe.ui.form.on("Company", { }, __('Manage')); } } - - frm.add_custom_button(__('Change Abbreviation'), () => { - frm.trigger('change_abbreviation'); - }, __('Manage')); } erpnext.company.set_chart_of_accounts_options(frm.doc); diff --git a/erpnext/setup/doctype/company/company.json b/erpnext/setup/doctype/company/company.json index 58cb52c04dd..63d96bf85e7 100644 --- a/erpnext/setup/doctype/company/company.json +++ b/erpnext/setup/doctype/company/company.json @@ -125,7 +125,8 @@ "label": "Abbr", "oldfieldname": "abbr", "oldfieldtype": "Data", - "reqd": 1 + "reqd": 1, + "set_only_once": 1 }, { "bold": 1, @@ -747,10 +748,11 @@ "image_field": "company_logo", "is_tree": 1, "links": [], - "modified": "2021-07-12 11:27:06.353860", + "modified": "2021-10-04 12:09:25.833133", "modified_by": "Administrator", "module": "Setup", "name": "Company", + "naming_rule": "By fieldname", "nsm_parent_field": "parent_company", "owner": "Administrator", "permissions": [ @@ -808,4 +810,4 @@ "sort_field": "modified", "sort_order": "ASC", "track_changes": 1 -} +} \ No newline at end of file diff --git a/erpnext/setup/doctype/company/company.py b/erpnext/setup/doctype/company/company.py index 6257d560ec8..dedd2d3f55c 100644 --- a/erpnext/setup/doctype/company/company.py +++ b/erpnext/setup/doctype/company/company.py @@ -1,9 +1,7 @@ # Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors # License: GNU General Public License v3. See license.txt -from __future__ import unicode_literals -import functools import json import os @@ -14,7 +12,6 @@ from frappe.cache_manager import clear_defaults_cache from frappe.contacts.address_and_contact import load_address_and_contact from frappe.utils import cint, formatdate, get_timestamp, today from frappe.utils.nestedset import NestedSet -from past.builtins import cmp from erpnext.accounts.doctype.account.account import get_account_currency from erpnext.setup.setup_wizard.operations.taxes_setup import setup_taxes_and_charges @@ -388,6 +385,7 @@ class Company(NestedSet): frappe.db.sql("delete from tabEmployee where company=%s", self.name) frappe.db.sql("delete from tabDepartment where company=%s", self.name) frappe.db.sql("delete from `tabTax Withholding Account` where company=%s", self.name) + frappe.db.sql("delete from `tabTransaction Deletion Record` where company=%s", self.name) # delete tax templates frappe.db.sql("delete from `tabSales Taxes and Charges Template` where company=%s", self.name) @@ -398,44 +396,6 @@ class Company(NestedSet): if not frappe.db.get_value('GL Entry', {'company': self.name}): frappe.db.sql("delete from `tabProcess Deferred Accounting` where company=%s", self.name) -@frappe.whitelist() -def enqueue_replace_abbr(company, old, new): - kwargs = dict(queue="long", company=company, old=old, new=new) - frappe.enqueue('erpnext.setup.doctype.company.company.replace_abbr', **kwargs) - - -@frappe.whitelist() -def replace_abbr(company, old, new): - new = new.strip() - if not new: - frappe.throw(_("Abbr can not be blank or space")) - - frappe.only_for("System Manager") - - def _rename_record(doc): - parts = doc[0].rsplit(" - ", 1) - if len(parts) == 1 or parts[1].lower() == old.lower(): - frappe.rename_doc(dt, doc[0], parts[0] + " - " + new, force=True) - - def _rename_records(dt): - # rename is expensive so let's be economical with memory usage - doc = (d for d in frappe.db.sql("select name from `tab%s` where company=%s" % (dt, '%s'), company)) - for d in doc: - _rename_record(d) - try: - frappe.db.auto_commit_on_many_writes = 1 - for dt in ["Warehouse", "Account", "Cost Center", "Department", - "Sales Taxes and Charges Template", "Purchase Taxes and Charges Template"]: - _rename_records(dt) - frappe.db.commit() - frappe.db.set_value("Company", company, "abbr", new) - - except Exception: - frappe.log_error(title=_('Abbreviation Rename Error')) - finally: - frappe.db.auto_commit_on_many_writes = 0 - - def get_name_with_abbr(name, company): company_abbr = frappe.get_cached_value('Company', company, "abbr") parts = name.split(" - ") @@ -453,7 +413,7 @@ def install_country_fixtures(company, country): frappe.get_attr(module_name)(company, False) except Exception as e: frappe.log_error() - frappe.throw(_("Failed to setup defaults for country {0}. Please contact support@erpnext.com").format(frappe.bold(country))) + frappe.throw(_("Failed to setup defaults for country {0}. Please contact support.").format(frappe.bold(country))) def update_company_current_month_sales(company): @@ -621,7 +581,7 @@ def get_default_company_address(name, sort_key='is_primary_address', existing_ad return existing_address if out: - return sorted(out, key = functools.cmp_to_key(lambda x,y: cmp(y[1], x[1])))[0][0] + return min(out, key=lambda x: x[1])[0] # find min by sort_key else: return None diff --git a/erpnext/setup/doctype/company/company_dashboard.py b/erpnext/setup/doctype/company/company_dashboard.py index 3afea098a0f..7cb0b1254f6 100644 --- a/erpnext/setup/doctype/company/company_dashboard.py +++ b/erpnext/setup/doctype/company/company_dashboard.py @@ -1,5 +1,3 @@ -from __future__ import unicode_literals - from frappe import _ diff --git a/erpnext/setup/doctype/company/test_company.py b/erpnext/setup/doctype/company/test_company.py index abc4689a20e..4ee94927381 100644 --- a/erpnext/setup/doctype/company/test_company.py +++ b/erpnext/setup/doctype/company/test_company.py @@ -1,6 +1,5 @@ # Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors # License: GNU General Public License v3. See license.txt -from __future__ import unicode_literals import json import unittest diff --git a/erpnext/setup/doctype/currency_exchange/currency_exchange.py b/erpnext/setup/doctype/currency_exchange/currency_exchange.py index 0b86e293778..4191935742f 100644 --- a/erpnext/setup/doctype/currency_exchange/currency_exchange.py +++ b/erpnext/setup/doctype/currency_exchange/currency_exchange.py @@ -3,7 +3,6 @@ # For license information, please see license.txt -from __future__ import unicode_literals from frappe import _, throw from frappe.model.document import Document diff --git a/erpnext/setup/doctype/customer_group/__init__.py b/erpnext/setup/doctype/customer_group/__init__.py index baffc488252..e69de29bb2d 100644 --- a/erpnext/setup/doctype/customer_group/__init__.py +++ b/erpnext/setup/doctype/customer_group/__init__.py @@ -1 +0,0 @@ -from __future__ import unicode_literals diff --git a/erpnext/setup/doctype/customer_group/customer_group.py b/erpnext/setup/doctype/customer_group/customer_group.py index 6e72810c561..5b917265d99 100644 --- a/erpnext/setup/doctype/customer_group/customer_group.py +++ b/erpnext/setup/doctype/customer_group/customer_group.py @@ -1,7 +1,6 @@ # Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors # License: GNU General Public License v3. See license.txt -from __future__ import unicode_literals import frappe from frappe import _ diff --git a/erpnext/setup/doctype/customer_group/test_customer_group.py b/erpnext/setup/doctype/customer_group/test_customer_group.py index e04b79b8f39..f02ae097928 100644 --- a/erpnext/setup/doctype/customer_group/test_customer_group.py +++ b/erpnext/setup/doctype/customer_group/test_customer_group.py @@ -1,6 +1,5 @@ # Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors # License: GNU General Public License v3. See license.txt -from __future__ import unicode_literals test_ignore = ["Price List"] diff --git a/erpnext/setup/doctype/email_digest/__init__.py b/erpnext/setup/doctype/email_digest/__init__.py index baffc488252..e69de29bb2d 100644 --- a/erpnext/setup/doctype/email_digest/__init__.py +++ b/erpnext/setup/doctype/email_digest/__init__.py @@ -1 +0,0 @@ -from __future__ import unicode_literals diff --git a/erpnext/setup/doctype/email_digest/email_digest.py b/erpnext/setup/doctype/email_digest/email_digest.py index 4e9a8ccad87..02f9156e196 100644 --- a/erpnext/setup/doctype/email_digest/email_digest.py +++ b/erpnext/setup/doctype/email_digest/email_digest.py @@ -1,7 +1,6 @@ # Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors # License: GNU General Public License v3. See license.txt -from __future__ import unicode_literals from datetime import timedelta diff --git a/erpnext/setup/doctype/email_digest/quotes.py b/erpnext/setup/doctype/email_digest/quotes.py index c77fe824ac9..fbd2d941179 100644 --- a/erpnext/setup/doctype/email_digest/quotes.py +++ b/erpnext/setup/doctype/email_digest/quotes.py @@ -1,6 +1,3 @@ -# -*- coding: utf-8 -*- -from __future__ import unicode_literals - import random diff --git a/erpnext/setup/doctype/email_digest/test_email_digest.py b/erpnext/setup/doctype/email_digest/test_email_digest.py index b3d0ce325b8..3fdf168a65e 100644 --- a/erpnext/setup/doctype/email_digest/test_email_digest.py +++ b/erpnext/setup/doctype/email_digest/test_email_digest.py @@ -1,7 +1,5 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors # See license.txt -from __future__ import unicode_literals import unittest diff --git a/erpnext/setup/doctype/email_digest_recipient/email_digest_recipient.py b/erpnext/setup/doctype/email_digest_recipient/email_digest_recipient.py index 5c8d695b6e5..06bf6273c07 100644 --- a/erpnext/setup/doctype/email_digest_recipient/email_digest_recipient.py +++ b/erpnext/setup/doctype/email_digest_recipient/email_digest_recipient.py @@ -1,8 +1,6 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2020, Frappe Technologies Pvt. Ltd. and contributors # For license information, please see license.txt -from __future__ import unicode_literals # import frappe from frappe.model.document import Document diff --git a/erpnext/setup/doctype/global_defaults/__init__.py b/erpnext/setup/doctype/global_defaults/__init__.py index baffc488252..e69de29bb2d 100644 --- a/erpnext/setup/doctype/global_defaults/__init__.py +++ b/erpnext/setup/doctype/global_defaults/__init__.py @@ -1 +0,0 @@ -from __future__ import unicode_literals diff --git a/erpnext/setup/doctype/global_defaults/global_defaults.py b/erpnext/setup/doctype/global_defaults/global_defaults.py index 66d3b9ee480..f0b720a42e1 100644 --- a/erpnext/setup/doctype/global_defaults/global_defaults.py +++ b/erpnext/setup/doctype/global_defaults/global_defaults.py @@ -1,7 +1,6 @@ # Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors # License: GNU General Public License v3. See license.txt -from __future__ import unicode_literals """Global Defaults""" import frappe diff --git a/erpnext/setup/doctype/global_defaults/test_global_defaults.py b/erpnext/setup/doctype/global_defaults/test_global_defaults.py index 70a7c08c111..a9d62ad30fa 100644 --- a/erpnext/setup/doctype/global_defaults/test_global_defaults.py +++ b/erpnext/setup/doctype/global_defaults/test_global_defaults.py @@ -1,7 +1,5 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2018, Frappe Technologies Pvt. Ltd. and Contributors # See license.txt -from __future__ import unicode_literals import unittest diff --git a/erpnext/setup/doctype/item_group/__init__.py b/erpnext/setup/doctype/item_group/__init__.py index baffc488252..e69de29bb2d 100644 --- a/erpnext/setup/doctype/item_group/__init__.py +++ b/erpnext/setup/doctype/item_group/__init__.py @@ -1 +0,0 @@ -from __future__ import unicode_literals diff --git a/erpnext/setup/doctype/item_group/item_group.py b/erpnext/setup/doctype/item_group/item_group.py index ddf3e662e0c..c94b3463fc8 100644 --- a/erpnext/setup/doctype/item_group/item_group.py +++ b/erpnext/setup/doctype/item_group/item_group.py @@ -1,7 +1,6 @@ # Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors # License: GNU General Public License v3. See license.txt -from __future__ import unicode_literals import copy @@ -39,11 +38,11 @@ class ItemGroup(NestedSet, WebsiteGenerator): self.parent_item_group = _('All Item Groups') self.make_route() + self.validate_item_group_defaults() def on_update(self): NestedSet.on_update(self) invalidate_cache_for(self) - self.validate_name_with_item() self.validate_one_root() self.delete_child_item_groups_key() @@ -67,10 +66,6 @@ class ItemGroup(NestedSet, WebsiteGenerator): WebsiteGenerator.on_trash(self) self.delete_child_item_groups_key() - def validate_name_with_item(self): - if frappe.db.exists("Item", self.name): - frappe.throw(frappe._("An item exists with same name ({0}), please change the item group name or rename the item").format(self.name), frappe.NameError) - def get_context(self, context): context.show_search=True context.page_length = cint(frappe.db.get_single_value('Products Settings', 'products_per_page')) or 6 @@ -99,7 +94,7 @@ class ItemGroup(NestedSet, WebsiteGenerator): filter_engine = ProductFiltersBuilder(self.name) context.field_filters = filter_engine.get_field_filters() - context.attribute_filters = filter_engine.get_attribute_fitlers() + context.attribute_filters = filter_engine.get_attribute_filters() context.update({ "parents": get_parent_item_groups(self.parent_item_group), @@ -134,6 +129,10 @@ class ItemGroup(NestedSet, WebsiteGenerator): def delete_child_item_groups_key(self): frappe.cache().hdel("child_item_groups", self.name) + def validate_item_group_defaults(self): + from erpnext.stock.doctype.item.item import validate_item_default_company_links + validate_item_default_company_links(self.item_group_defaults) + @frappe.whitelist(allow_guest=True) def get_product_list_for_group(product_group=None, start=0, limit=10, search=None): if product_group: diff --git a/erpnext/setup/doctype/item_group/test_item_group.py b/erpnext/setup/doctype/item_group/test_item_group.py index a816f391c62..f6e9ed4ce59 100644 --- a/erpnext/setup/doctype/item_group/test_item_group.py +++ b/erpnext/setup/doctype/item_group/test_item_group.py @@ -1,7 +1,6 @@ # Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors # License: GNU General Public License v3. See license.txt -from __future__ import print_function, unicode_literals import unittest diff --git a/erpnext/setup/doctype/item_group/test_records.json b/erpnext/setup/doctype/item_group/test_records.json index 146da87bddc..ce1d718375a 100644 --- a/erpnext/setup/doctype/item_group/test_records.json +++ b/erpnext/setup/doctype/item_group/test_records.json @@ -1,73 +1,74 @@ [ { - "doctype": "Item Group", - "is_group": 0, - "item_group_name": "_Test Item Group", + "doctype": "Item Group", + "is_group": 0, + "item_group_name": "_Test Item Group", "parent_item_group": "All Item Groups", "item_group_defaults": [{ "company": "_Test Company", "buying_cost_center": "_Test Cost Center 2 - _TC", - "selling_cost_center": "_Test Cost Center 2 - _TC" + "selling_cost_center": "_Test Cost Center 2 - _TC", + "default_warehouse": "_Test Warehouse - _TC" }] - }, + }, { - "doctype": "Item Group", - "is_group": 0, - "item_group_name": "_Test Item Group Desktops", + "doctype": "Item Group", + "is_group": 0, + "item_group_name": "_Test Item Group Desktops", "parent_item_group": "All Item Groups" - }, + }, { - "doctype": "Item Group", - "is_group": 1, - "item_group_name": "_Test Item Group A", + "doctype": "Item Group", + "is_group": 1, + "item_group_name": "_Test Item Group A", "parent_item_group": "All Item Groups" - }, + }, { - "doctype": "Item Group", - "is_group": 1, - "item_group_name": "_Test Item Group B", + "doctype": "Item Group", + "is_group": 1, + "item_group_name": "_Test Item Group B", "parent_item_group": "All Item Groups" - }, + }, { - "doctype": "Item Group", - "is_group": 1, - "item_group_name": "_Test Item Group B - 1", + "doctype": "Item Group", + "is_group": 1, + "item_group_name": "_Test Item Group B - 1", "parent_item_group": "_Test Item Group B" - }, + }, { - "doctype": "Item Group", - "is_group": 1, - "item_group_name": "_Test Item Group B - 2", + "doctype": "Item Group", + "is_group": 1, + "item_group_name": "_Test Item Group B - 2", "parent_item_group": "_Test Item Group B" - }, + }, { - "doctype": "Item Group", - "is_group": 0, - "item_group_name": "_Test Item Group B - 3", + "doctype": "Item Group", + "is_group": 0, + "item_group_name": "_Test Item Group B - 3", "parent_item_group": "_Test Item Group B" - }, + }, { - "doctype": "Item Group", - "is_group": 1, - "item_group_name": "_Test Item Group C", + "doctype": "Item Group", + "is_group": 1, + "item_group_name": "_Test Item Group C", "parent_item_group": "All Item Groups" - }, + }, { - "doctype": "Item Group", - "is_group": 1, - "item_group_name": "_Test Item Group C - 1", + "doctype": "Item Group", + "is_group": 1, + "item_group_name": "_Test Item Group C - 1", "parent_item_group": "_Test Item Group C" - }, + }, { - "doctype": "Item Group", - "is_group": 1, - "item_group_name": "_Test Item Group C - 2", + "doctype": "Item Group", + "is_group": 1, + "item_group_name": "_Test Item Group C - 2", "parent_item_group": "_Test Item Group C" - }, + }, { - "doctype": "Item Group", - "is_group": 1, - "item_group_name": "_Test Item Group D", + "doctype": "Item Group", + "is_group": 1, + "item_group_name": "_Test Item Group D", "parent_item_group": "All Item Groups" }, { @@ -104,4 +105,4 @@ } ] } -] \ No newline at end of file +] diff --git a/erpnext/setup/doctype/naming_series/__init__.py b/erpnext/setup/doctype/naming_series/__init__.py index baffc488252..e69de29bb2d 100644 --- a/erpnext/setup/doctype/naming_series/__init__.py +++ b/erpnext/setup/doctype/naming_series/__init__.py @@ -1 +0,0 @@ -from __future__ import unicode_literals diff --git a/erpnext/setup/doctype/naming_series/naming_series.py b/erpnext/setup/doctype/naming_series/naming_series.py index 005cfec769a..986b4e87ff0 100644 --- a/erpnext/setup/doctype/naming_series/naming_series.py +++ b/erpnext/setup/doctype/naming_series/naming_series.py @@ -1,7 +1,6 @@ # Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors # License: GNU General Public License v3. See license.txt -from __future__ import unicode_literals import frappe from frappe import _, msgprint, throw @@ -181,11 +180,11 @@ class NamingSeries(Document): prefix = parse_naming_series(parts) return prefix -def set_by_naming_series(doctype, fieldname, naming_series, hide_name_field=True): +def set_by_naming_series(doctype, fieldname, naming_series, hide_name_field=True, make_mandatory=1): from frappe.custom.doctype.property_setter.property_setter import make_property_setter if naming_series: make_property_setter(doctype, "naming_series", "hidden", 0, "Check", validate_fields_for_doctype=False) - make_property_setter(doctype, "naming_series", "reqd", 1, "Check", validate_fields_for_doctype=False) + make_property_setter(doctype, "naming_series", "reqd", make_mandatory, "Check", validate_fields_for_doctype=False) # set values for mandatory try: diff --git a/erpnext/setup/doctype/party_type/party_type.py b/erpnext/setup/doctype/party_type/party_type.py index 8424c7fe938..d0d2946e94a 100644 --- a/erpnext/setup/doctype/party_type/party_type.py +++ b/erpnext/setup/doctype/party_type/party_type.py @@ -1,8 +1,6 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2015, Frappe Technologies and contributors # For license information, please see license.txt -from __future__ import unicode_literals import frappe from frappe.model.document import Document diff --git a/erpnext/setup/doctype/party_type/test_party_type.py b/erpnext/setup/doctype/party_type/test_party_type.py index e5f2908eb46..a9a3db8777e 100644 --- a/erpnext/setup/doctype/party_type/test_party_type.py +++ b/erpnext/setup/doctype/party_type/test_party_type.py @@ -1,7 +1,5 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors # See license.txt -from __future__ import unicode_literals import unittest diff --git a/erpnext/setup/doctype/print_heading/__init__.py b/erpnext/setup/doctype/print_heading/__init__.py index baffc488252..e69de29bb2d 100644 --- a/erpnext/setup/doctype/print_heading/__init__.py +++ b/erpnext/setup/doctype/print_heading/__init__.py @@ -1 +0,0 @@ -from __future__ import unicode_literals diff --git a/erpnext/setup/doctype/print_heading/print_heading.py b/erpnext/setup/doctype/print_heading/print_heading.py index cf25638608b..3a2f15f4b2a 100644 --- a/erpnext/setup/doctype/print_heading/print_heading.py +++ b/erpnext/setup/doctype/print_heading/print_heading.py @@ -1,7 +1,6 @@ # Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors # License: GNU General Public License v3. See license.txt -from __future__ import unicode_literals from frappe.model.document import Document diff --git a/erpnext/setup/doctype/print_heading/test_print_heading.py b/erpnext/setup/doctype/print_heading/test_print_heading.py index 06f801a654e..04de08d2697 100644 --- a/erpnext/setup/doctype/print_heading/test_print_heading.py +++ b/erpnext/setup/doctype/print_heading/test_print_heading.py @@ -1,6 +1,5 @@ # Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors # License: GNU General Public License v3. See license.txt -from __future__ import unicode_literals import frappe diff --git a/erpnext/setup/doctype/quotation_lost_reason/__init__.py b/erpnext/setup/doctype/quotation_lost_reason/__init__.py index baffc488252..e69de29bb2d 100644 --- a/erpnext/setup/doctype/quotation_lost_reason/__init__.py +++ b/erpnext/setup/doctype/quotation_lost_reason/__init__.py @@ -1 +0,0 @@ -from __future__ import unicode_literals diff --git a/erpnext/setup/doctype/quotation_lost_reason/quotation_lost_reason.py b/erpnext/setup/doctype/quotation_lost_reason/quotation_lost_reason.py index 9131cc334a7..651705c6e5b 100644 --- a/erpnext/setup/doctype/quotation_lost_reason/quotation_lost_reason.py +++ b/erpnext/setup/doctype/quotation_lost_reason/quotation_lost_reason.py @@ -1,7 +1,6 @@ # Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors # License: GNU General Public License v3. See license.txt -from __future__ import unicode_literals from frappe.model.document import Document diff --git a/erpnext/setup/doctype/quotation_lost_reason/test_quotation_lost_reason.py b/erpnext/setup/doctype/quotation_lost_reason/test_quotation_lost_reason.py index ab8d61f1ebe..9330ba85870 100644 --- a/erpnext/setup/doctype/quotation_lost_reason/test_quotation_lost_reason.py +++ b/erpnext/setup/doctype/quotation_lost_reason/test_quotation_lost_reason.py @@ -1,6 +1,5 @@ # Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors # License: GNU General Public License v3. See license.txt -from __future__ import unicode_literals import frappe diff --git a/erpnext/setup/doctype/quotation_lost_reason_detail/quotation_lost_reason_detail.py b/erpnext/setup/doctype/quotation_lost_reason_detail/quotation_lost_reason_detail.py index 434f24ea925..dda64e9c624 100644 --- a/erpnext/setup/doctype/quotation_lost_reason_detail/quotation_lost_reason_detail.py +++ b/erpnext/setup/doctype/quotation_lost_reason_detail/quotation_lost_reason_detail.py @@ -1,8 +1,6 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2020, Frappe Technologies Pvt. Ltd. and contributors # For license information, please see license.txt -from __future__ import unicode_literals # import frappe from frappe.model.document import Document diff --git a/erpnext/setup/doctype/sales_partner/__init__.py b/erpnext/setup/doctype/sales_partner/__init__.py index baffc488252..e69de29bb2d 100644 --- a/erpnext/setup/doctype/sales_partner/__init__.py +++ b/erpnext/setup/doctype/sales_partner/__init__.py @@ -1 +0,0 @@ -from __future__ import unicode_literals diff --git a/erpnext/setup/doctype/sales_partner/sales_partner.py b/erpnext/setup/doctype/sales_partner/sales_partner.py index 6c741a8fb44..d2ec49dd6c3 100644 --- a/erpnext/setup/doctype/sales_partner/sales_partner.py +++ b/erpnext/setup/doctype/sales_partner/sales_partner.py @@ -1,7 +1,6 @@ # Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors # License: GNU General Public License v3. See license.txt -from __future__ import unicode_literals import frappe from frappe.contacts.address_and_contact import load_address_and_contact diff --git a/erpnext/setup/doctype/sales_partner/test_sales_partner.py b/erpnext/setup/doctype/sales_partner/test_sales_partner.py index 6ece2390405..80ef3680147 100644 --- a/erpnext/setup/doctype/sales_partner/test_sales_partner.py +++ b/erpnext/setup/doctype/sales_partner/test_sales_partner.py @@ -1,6 +1,5 @@ # Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors # License: GNU General Public License v3. See license.txt -from __future__ import unicode_literals import frappe diff --git a/erpnext/setup/doctype/sales_person/__init__.py b/erpnext/setup/doctype/sales_person/__init__.py index baffc488252..e69de29bb2d 100644 --- a/erpnext/setup/doctype/sales_person/__init__.py +++ b/erpnext/setup/doctype/sales_person/__init__.py @@ -1 +0,0 @@ -from __future__ import unicode_literals diff --git a/erpnext/setup/doctype/sales_person/sales_person.py b/erpnext/setup/doctype/sales_person/sales_person.py index c7cad6bb998..b79a566578d 100644 --- a/erpnext/setup/doctype/sales_person/sales_person.py +++ b/erpnext/setup/doctype/sales_person/sales_person.py @@ -1,7 +1,6 @@ # Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors # License: GNU General Public License v3. See license.txt -from __future__ import unicode_literals import frappe from frappe import _ diff --git a/erpnext/setup/doctype/sales_person/sales_person_dashboard.py b/erpnext/setup/doctype/sales_person/sales_person_dashboard.py index 61c1ba46d35..e946406e638 100644 --- a/erpnext/setup/doctype/sales_person/sales_person_dashboard.py +++ b/erpnext/setup/doctype/sales_person/sales_person_dashboard.py @@ -1,5 +1,3 @@ -from __future__ import unicode_literals - from frappe import _ diff --git a/erpnext/setup/doctype/sales_person/test_sales_person.py b/erpnext/setup/doctype/sales_person/test_sales_person.py index 497aaad74f8..786d2cac4da 100644 --- a/erpnext/setup/doctype/sales_person/test_sales_person.py +++ b/erpnext/setup/doctype/sales_person/test_sales_person.py @@ -1,6 +1,5 @@ # Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors # License: GNU General Public License v3. See license.txt -from __future__ import unicode_literals test_dependencies = ["Employee"] diff --git a/erpnext/setup/doctype/supplier_group/__init__.py b/erpnext/setup/doctype/supplier_group/__init__.py index baffc488252..e69de29bb2d 100644 --- a/erpnext/setup/doctype/supplier_group/__init__.py +++ b/erpnext/setup/doctype/supplier_group/__init__.py @@ -1 +0,0 @@ -from __future__ import unicode_literals diff --git a/erpnext/setup/doctype/supplier_group/supplier_group.py b/erpnext/setup/doctype/supplier_group/supplier_group.py index 0ca35257926..381e1250c82 100644 --- a/erpnext/setup/doctype/supplier_group/supplier_group.py +++ b/erpnext/setup/doctype/supplier_group/supplier_group.py @@ -1,8 +1,6 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2018, Frappe Technologies Pvt. Ltd. and contributors # For license information, please see license.txt -from __future__ import unicode_literals import frappe from frappe.utils.nestedset import NestedSet, get_root_of diff --git a/erpnext/setup/doctype/supplier_group/test_supplier_group.py b/erpnext/setup/doctype/supplier_group/test_supplier_group.py index b3a636635ec..283b3bfec3c 100644 --- a/erpnext/setup/doctype/supplier_group/test_supplier_group.py +++ b/erpnext/setup/doctype/supplier_group/test_supplier_group.py @@ -1,7 +1,5 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2018, Frappe Technologies Pvt. Ltd. and Contributors # See license.txt -from __future__ import unicode_literals import frappe diff --git a/erpnext/setup/doctype/target_detail/__init__.py b/erpnext/setup/doctype/target_detail/__init__.py index baffc488252..e69de29bb2d 100644 --- a/erpnext/setup/doctype/target_detail/__init__.py +++ b/erpnext/setup/doctype/target_detail/__init__.py @@ -1 +0,0 @@ -from __future__ import unicode_literals diff --git a/erpnext/setup/doctype/target_detail/target_detail.py b/erpnext/setup/doctype/target_detail/target_detail.py index 89cd814f2d1..e27f5b6020d 100644 --- a/erpnext/setup/doctype/target_detail/target_detail.py +++ b/erpnext/setup/doctype/target_detail/target_detail.py @@ -1,7 +1,6 @@ # Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors # License: GNU General Public License v3. See license.txt -from __future__ import unicode_literals from frappe.model.document import Document diff --git a/erpnext/setup/doctype/terms_and_conditions/__init__.py b/erpnext/setup/doctype/terms_and_conditions/__init__.py index baffc488252..e69de29bb2d 100644 --- a/erpnext/setup/doctype/terms_and_conditions/__init__.py +++ b/erpnext/setup/doctype/terms_and_conditions/__init__.py @@ -1 +0,0 @@ -from __future__ import unicode_literals diff --git a/erpnext/setup/doctype/terms_and_conditions/terms_and_conditions.py b/erpnext/setup/doctype/terms_and_conditions/terms_and_conditions.py index 8c9059f61ef..658f286f7c3 100644 --- a/erpnext/setup/doctype/terms_and_conditions/terms_and_conditions.py +++ b/erpnext/setup/doctype/terms_and_conditions/terms_and_conditions.py @@ -1,7 +1,6 @@ # Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors # License: GNU General Public License v3. See license.txt -from __future__ import unicode_literals import json @@ -10,7 +9,6 @@ from frappe import _, throw from frappe.model.document import Document from frappe.utils import cint from frappe.utils.jinja import validate_template -from six import string_types class TermsandConditions(Document): @@ -22,7 +20,7 @@ class TermsandConditions(Document): @frappe.whitelist() def get_terms_and_conditions(template_name, doc): - if isinstance(doc, string_types): + if isinstance(doc, str): doc = json.loads(doc) terms_and_conditions = frappe.get_doc("Terms and Conditions", template_name) diff --git a/erpnext/setup/doctype/terms_and_conditions/test_terms_and_conditions.py b/erpnext/setup/doctype/terms_and_conditions/test_terms_and_conditions.py index abfa9214d64..ca9e6c1aef8 100644 --- a/erpnext/setup/doctype/terms_and_conditions/test_terms_and_conditions.py +++ b/erpnext/setup/doctype/terms_and_conditions/test_terms_and_conditions.py @@ -1,6 +1,5 @@ # Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors # License: GNU General Public License v3. See license.txt -from __future__ import unicode_literals import frappe diff --git a/erpnext/setup/doctype/territory/__init__.py b/erpnext/setup/doctype/territory/__init__.py index baffc488252..e69de29bb2d 100644 --- a/erpnext/setup/doctype/territory/__init__.py +++ b/erpnext/setup/doctype/territory/__init__.py @@ -1 +0,0 @@ -from __future__ import unicode_literals diff --git a/erpnext/setup/doctype/territory/territory.py b/erpnext/setup/doctype/territory/territory.py index f61796b9bdf..4c47d829e98 100644 --- a/erpnext/setup/doctype/territory/territory.py +++ b/erpnext/setup/doctype/territory/territory.py @@ -1,7 +1,6 @@ # Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors # License: GNU General Public License v3. See license.txt -from __future__ import unicode_literals import frappe from frappe import _ diff --git a/erpnext/setup/doctype/territory/test_territory.py b/erpnext/setup/doctype/territory/test_territory.py index a3aa866fff3..a18b7bf70ef 100644 --- a/erpnext/setup/doctype/territory/test_territory.py +++ b/erpnext/setup/doctype/territory/test_territory.py @@ -1,6 +1,5 @@ # Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors # License: GNU General Public License v3. See license.txt -from __future__ import unicode_literals import frappe diff --git a/erpnext/setup/doctype/transaction_deletion_record/test_transaction_deletion_record.py b/erpnext/setup/doctype/transaction_deletion_record/test_transaction_deletion_record.py index aa0f79b4c86..095c3d0b6fb 100644 --- a/erpnext/setup/doctype/transaction_deletion_record/test_transaction_deletion_record.py +++ b/erpnext/setup/doctype/transaction_deletion_record/test_transaction_deletion_record.py @@ -1,7 +1,5 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2021, Frappe Technologies Pvt. Ltd. and Contributors # See license.txt -from __future__ import unicode_literals import unittest diff --git a/erpnext/setup/doctype/transaction_deletion_record/transaction_deletion_record.py b/erpnext/setup/doctype/transaction_deletion_record/transaction_deletion_record.py index efb038faccc..83ce042cde0 100644 --- a/erpnext/setup/doctype/transaction_deletion_record/transaction_deletion_record.py +++ b/erpnext/setup/doctype/transaction_deletion_record/transaction_deletion_record.py @@ -1,8 +1,6 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2021, Frappe Technologies Pvt. Ltd. and contributors # For license information, please see license.txt -from __future__ import unicode_literals import frappe from frappe import _ diff --git a/erpnext/setup/doctype/transaction_deletion_record_item/transaction_deletion_record_item.py b/erpnext/setup/doctype/transaction_deletion_record_item/transaction_deletion_record_item.py index a113d504538..92ca8a2ac73 100644 --- a/erpnext/setup/doctype/transaction_deletion_record_item/transaction_deletion_record_item.py +++ b/erpnext/setup/doctype/transaction_deletion_record_item/transaction_deletion_record_item.py @@ -1,8 +1,6 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2021, Frappe Technologies Pvt. Ltd. and contributors # For license information, please see license.txt -from __future__ import unicode_literals # import frappe from frappe.model.document import Document diff --git a/erpnext/setup/doctype/uom/__init__.py b/erpnext/setup/doctype/uom/__init__.py index baffc488252..e69de29bb2d 100644 --- a/erpnext/setup/doctype/uom/__init__.py +++ b/erpnext/setup/doctype/uom/__init__.py @@ -1 +0,0 @@ -from __future__ import unicode_literals diff --git a/erpnext/setup/doctype/uom/test_uom.py b/erpnext/setup/doctype/uom/test_uom.py index e222c134942..feb43293079 100644 --- a/erpnext/setup/doctype/uom/test_uom.py +++ b/erpnext/setup/doctype/uom/test_uom.py @@ -1,6 +1,5 @@ # Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors # License: GNU General Public License v3. See license.txt -from __future__ import unicode_literals import frappe diff --git a/erpnext/setup/doctype/uom/uom.json b/erpnext/setup/doctype/uom/uom.json index 3a4e7f6dc4b..844a11f1397 100644 --- a/erpnext/setup/doctype/uom/uom.json +++ b/erpnext/setup/doctype/uom/uom.json @@ -1,164 +1,82 @@ { - "allow_copy": 0, - "allow_guest_to_view": 0, + "actions": [], "allow_import": 1, "allow_rename": 1, "autoname": "field:uom_name", - "beta": 0, "creation": "2013-01-10 16:34:24", - "custom": 0, - "docstatus": 0, "doctype": "DocType", "document_type": "Setup", - "editable_grid": 0, + "engine": "InnoDB", + "field_order": [ + "enabled", + "uom_name", + "must_be_whole_number" + ], "fields": [ { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, "fieldname": "uom_name", "fieldtype": "Data", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, "in_list_view": 1, - "in_standard_filter": 0, "label": "UOM Name", - "length": 0, - "no_copy": 0, "oldfieldname": "uom_name", "oldfieldtype": "Data", - "permlevel": 0, - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, "reqd": 1, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, "unique": 1 }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, + "default": "0", "description": "Check this to disallow fractions. (for Nos)", "fieldname": "must_be_whole_number", "fieldtype": "Check", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "label": "Must be Whole Number", - "length": 0, - "no_copy": 0, - "permlevel": 0, - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 + "label": "Must be Whole Number" + }, + { + "default": "1", + "fieldname": "enabled", + "fieldtype": "Check", + "label": "Enabled" } ], - "has_web_view": 0, - "hide_heading": 0, - "hide_toolbar": 0, "icon": "fa fa-compass", "idx": 1, - "image_view": 0, - "in_create": 0, - "is_submittable": 0, - "issingle": 0, - "istable": 0, - "max_attachments": 0, - "modified": "2018-08-29 06:35:56.143361", + "links": [], + "modified": "2021-10-18 14:07:43.722144", "modified_by": "Administrator", "module": "Setup", "name": "UOM", + "naming_rule": "By fieldname", "owner": "Administrator", "permissions": [ { - "amend": 0, - "cancel": 0, "create": 1, "delete": 1, "email": 1, "export": 1, - "if_owner": 0, "import": 1, - "permlevel": 0, "print": 1, "read": 1, "report": 1, "role": "Item Manager", - "set_user_permissions": 0, "share": 1, - "submit": 0, "write": 1 }, { - "amend": 0, - "cancel": 0, - "create": 0, - "delete": 0, "email": 1, - "export": 0, - "if_owner": 0, - "import": 0, - "permlevel": 0, "print": 1, "read": 1, "report": 1, - "role": "Stock Manager", - "set_user_permissions": 0, - "share": 0, - "submit": 0, - "write": 0 + "role": "Stock Manager" }, { - "amend": 0, - "cancel": 0, - "create": 0, - "delete": 0, "email": 1, - "export": 0, - "if_owner": 0, - "import": 0, - "permlevel": 0, "print": 1, "read": 1, "report": 1, - "role": "Stock User", - "set_user_permissions": 0, - "share": 0, - "submit": 0, - "write": 0 + "role": "Stock User" } ], "quick_entry": 1, - "read_only": 0, - "read_only_onload": 0, "show_name_in_global_search": 1, - "sort_order": "ASC", - "track_changes": 0, - "track_seen": 0, - "track_views": 0 + "sort_field": "modified", + "sort_order": "ASC" } \ No newline at end of file diff --git a/erpnext/setup/doctype/uom/uom.py b/erpnext/setup/doctype/uom/uom.py index f0e97b34e25..ddb512a0852 100644 --- a/erpnext/setup/doctype/uom/uom.py +++ b/erpnext/setup/doctype/uom/uom.py @@ -1,7 +1,6 @@ # Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors # License: GNU General Public License v3. See license.txt -from __future__ import unicode_literals from frappe.model.document import Document diff --git a/erpnext/setup/doctype/uom_conversion_factor/test_uom_conversion_factor.py b/erpnext/setup/doctype/uom_conversion_factor/test_uom_conversion_factor.py index 33795d6b5b2..5683b5bc30d 100644 --- a/erpnext/setup/doctype/uom_conversion_factor/test_uom_conversion_factor.py +++ b/erpnext/setup/doctype/uom_conversion_factor/test_uom_conversion_factor.py @@ -1,7 +1,5 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2018, Frappe Technologies Pvt. Ltd. and Contributors # See license.txt -from __future__ import unicode_literals import unittest diff --git a/erpnext/setup/doctype/uom_conversion_factor/uom_conversion_factor.py b/erpnext/setup/doctype/uom_conversion_factor/uom_conversion_factor.py index 45342e9fee9..12642fe7e25 100644 --- a/erpnext/setup/doctype/uom_conversion_factor/uom_conversion_factor.py +++ b/erpnext/setup/doctype/uom_conversion_factor/uom_conversion_factor.py @@ -1,8 +1,6 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2018, Frappe Technologies Pvt. Ltd. and contributors # For license information, please see license.txt -from __future__ import unicode_literals from frappe.model.document import Document diff --git a/erpnext/setup/doctype/website_item_group/website_item_group.py b/erpnext/setup/doctype/website_item_group/website_item_group.py index 2f720134484..87fcb984530 100644 --- a/erpnext/setup/doctype/website_item_group/website_item_group.py +++ b/erpnext/setup/doctype/website_item_group/website_item_group.py @@ -3,7 +3,6 @@ # For license information, please see license.txt -from __future__ import unicode_literals from frappe.model.document import Document diff --git a/erpnext/setup/install.py b/erpnext/setup/install.py index cdc83c14620..86c9b3f178d 100644 --- a/erpnext/setup/install.py +++ b/erpnext/setup/install.py @@ -1,7 +1,6 @@ # Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors # License: GNU General Public License v3. See license.txt -from __future__ import print_function, unicode_literals import frappe from frappe import _ @@ -9,7 +8,6 @@ from frappe.custom.doctype.custom_field.custom_field import create_custom_field from frappe.desk.page.setup_wizard.setup_wizard import add_all_roles_to from frappe.installer import update_site_config from frappe.utils import cint -from six import iteritems from erpnext.accounts.doctype.cash_flow_mapper.default_cash_flow_mapper import DEFAULT_MAPPERS from erpnext.setup.default_energy_point_rules import get_default_energy_point_rules @@ -174,12 +172,12 @@ def add_non_standard_user_types(): user_types = get_user_types_data() user_type_limit = {} - for user_type, data in iteritems(user_types): + for user_type, data in user_types.items(): user_type_limit.setdefault(frappe.scrub(user_type), 10) update_site_config('user_type_doctype_limit', user_type_limit) - for user_type, data in iteritems(user_types): + for user_type, data in user_types.items(): create_custom_role(data) create_user_type(user_type, data) @@ -229,7 +227,7 @@ def create_user_type(user_type, data): doc.save(ignore_permissions=True) def create_role_permissions_for_doctype(doc, data): - for doctype, perms in iteritems(data.get('doctypes')): + for doctype, perms in data.get('doctypes').items(): args = {'document_type': doctype} for perm in perms: args[perm] = 1 diff --git a/erpnext/setup/page/__init__.py b/erpnext/setup/page/__init__.py index baffc488252..e69de29bb2d 100644 --- a/erpnext/setup/page/__init__.py +++ b/erpnext/setup/page/__init__.py @@ -1 +0,0 @@ -from __future__ import unicode_literals diff --git a/erpnext/setup/setup_wizard/data/country_wise_tax.json b/erpnext/setup/setup_wizard/data/country_wise_tax.json index 34af093a231..14b79510c12 100644 --- a/erpnext/setup/setup_wizard/data/country_wise_tax.json +++ b/erpnext/setup/setup_wizard/data/country_wise_tax.json @@ -1195,7 +1195,7 @@ "*": { "item_tax_templates": [ { - "title": "GST 9%", + "title": "GST 18%", "taxes": [ { "tax_type": { @@ -2116,6 +2116,10 @@ }, "Saudi Arabia": { + "KSA VAT 15%": { + "account_name": "VAT 15%", + "tax_rate": 15.00 + }, "KSA VAT 5%": { "account_name": "VAT 5%", "tax_rate": 5.00 diff --git a/erpnext/setup/setup_wizard/data/dashboard_charts.py b/erpnext/setup/setup_wizard/data/dashboard_charts.py index 5369bbab356..6cb15b2a46c 100644 --- a/erpnext/setup/setup_wizard/data/dashboard_charts.py +++ b/erpnext/setup/setup_wizard/data/dashboard_charts.py @@ -1,5 +1,3 @@ -from __future__ import unicode_literals - import json import frappe diff --git a/erpnext/setup/setup_wizard/data/industry_type.py b/erpnext/setup/setup_wizard/data/industry_type.py index 2c83a5c721c..ecd8b001991 100644 --- a/erpnext/setup/setup_wizard/data/industry_type.py +++ b/erpnext/setup/setup_wizard/data/industry_type.py @@ -1,5 +1,3 @@ -from __future__ import unicode_literals - from frappe import _ diff --git a/erpnext/setup/setup_wizard/operations/company_setup.py b/erpnext/setup/setup_wizard/operations/company_setup.py index bea3906ebaf..358b9218312 100644 --- a/erpnext/setup/setup_wizard/operations/company_setup.py +++ b/erpnext/setup/setup_wizard/operations/company_setup.py @@ -1,7 +1,6 @@ # Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors # License: GNU General Public License v3. See license.txt -from __future__ import unicode_literals import frappe from frappe import _ from frappe.utils import cstr, getdate diff --git a/erpnext/setup/setup_wizard/operations/default_website.py b/erpnext/setup/setup_wizard/operations/default_website.py index 2288ae06746..c11910b584c 100644 --- a/erpnext/setup/setup_wizard/operations/default_website.py +++ b/erpnext/setup/setup_wizard/operations/default_website.py @@ -1,7 +1,6 @@ # Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors # License: GNU General Public License v3. See license.txt -from __future__ import unicode_literals import frappe from frappe import _ diff --git a/erpnext/setup/setup_wizard/operations/defaults_setup.py b/erpnext/setup/setup_wizard/operations/defaults_setup.py index 6dd0fb1403f..e4b1fa26ae0 100644 --- a/erpnext/setup/setup_wizard/operations/defaults_setup.py +++ b/erpnext/setup/setup_wizard/operations/defaults_setup.py @@ -1,7 +1,6 @@ # Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors # License: GNU General Public License v3. See license.txt -from __future__ import unicode_literals import frappe from frappe import _ from frappe.utils import cstr, getdate @@ -62,6 +61,13 @@ def set_default_settings(args): hr_settings.emp_created_by = "Naming Series" hr_settings.leave_approval_notification_template = _("Leave Approval Notification") hr_settings.leave_status_notification_template = _("Leave Status Notification") + + hr_settings.send_interview_reminder = 1 + hr_settings.interview_reminder_template = _("Interview Reminder") + hr_settings.remind_before = "00:15:00" + + hr_settings.send_interview_feedback_reminder = 1 + hr_settings.feedback_reminder_notification_template = _("Interview Feedback Reminder") hr_settings.save() def set_no_copy_fields_in_variant_settings(): diff --git a/erpnext/setup/setup_wizard/operations/install_fixtures.py b/erpnext/setup/setup_wizard/operations/install_fixtures.py index 907967c83fd..503aeacd015 100644 --- a/erpnext/setup/setup_wizard/operations/install_fixtures.py +++ b/erpnext/setup/setup_wizard/operations/install_fixtures.py @@ -1,7 +1,6 @@ # Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors # License: GNU General Public License v3. See license.txt -from __future__ import unicode_literals import json import os @@ -202,7 +201,6 @@ def install(country=None): {'doctype': "Party Type", "party_type": "Student", "account_type": "Receivable"}, {'doctype': "Party Type", "party_type": "Donor", "account_type": "Receivable"}, - {'doctype': "Opportunity Type", "name": "Hub"}, {'doctype': "Opportunity Type", "name": _("Sales")}, {'doctype': "Opportunity Type", "name": _("Support")}, {'doctype': "Opportunity Type", "name": _("Maintenance")}, @@ -264,16 +262,26 @@ def install(country=None): base_path = frappe.get_app_path("erpnext", "hr", "doctype") response = frappe.read_file(os.path.join(base_path, "leave_application/leave_application_email_template.html")) - records += [{'doctype': 'Email Template', 'name': _("Leave Approval Notification"), 'response': response,\ + records += [{'doctype': 'Email Template', 'name': _("Leave Approval Notification"), 'response': response, 'subject': _("Leave Approval Notification"), 'owner': frappe.session.user}] - records += [{'doctype': 'Email Template', 'name': _("Leave Status Notification"), 'response': response,\ + records += [{'doctype': 'Email Template', 'name': _("Leave Status Notification"), 'response': response, 'subject': _("Leave Status Notification"), 'owner': frappe.session.user}] + response = frappe.read_file(os.path.join(base_path, "interview/interview_reminder_notification_template.html")) + + records += [{'doctype': 'Email Template', 'name': _('Interview Reminder'), 'response': response, + 'subject': _('Interview Reminder'), 'owner': frappe.session.user}] + + response = frappe.read_file(os.path.join(base_path, "interview/interview_feedback_reminder_template.html")) + + records += [{'doctype': 'Email Template', 'name': _('Interview Feedback Reminder'), 'response': response, + 'subject': _('Interview Feedback Reminder'), 'owner': frappe.session.user}] + base_path = frappe.get_app_path("erpnext", "stock", "doctype") response = frappe.read_file(os.path.join(base_path, "delivery_trip/dispatch_notification_template.html")) - records += [{'doctype': 'Email Template', 'name': _("Dispatch Notification"), 'response': response,\ + records += [{'doctype': 'Email Template', 'name': _("Dispatch Notification"), 'response': response, 'subject': _("Your order is out for delivery!"), 'owner': frappe.session.user}] # Records for the Supplier Scorecard @@ -317,6 +325,14 @@ def update_hr_defaults(): hr_settings.emp_created_by = "Naming Series" hr_settings.leave_approval_notification_template = _("Leave Approval Notification") hr_settings.leave_status_notification_template = _("Leave Status Notification") + + hr_settings.send_interview_reminder = 1 + hr_settings.interview_reminder_template = _("Interview Reminder") + hr_settings.remind_before = "00:15:00" + + hr_settings.send_interview_feedback_reminder = 1 + hr_settings.feedback_reminder_notification_template = _("Interview Feedback Reminder") + hr_settings.save() def update_item_variant_settings(): diff --git a/erpnext/setup/setup_wizard/operations/sample_data.py b/erpnext/setup/setup_wizard/operations/sample_data.py index 3aef40d3ebb..16859947741 100644 --- a/erpnext/setup/setup_wizard/operations/sample_data.py +++ b/erpnext/setup/setup_wizard/operations/sample_data.py @@ -1,7 +1,6 @@ # Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors # License: GNU General Public License v3. See license.txt -from __future__ import unicode_literals import json import os diff --git a/erpnext/setup/setup_wizard/operations/taxes_setup.py b/erpnext/setup/setup_wizard/operations/taxes_setup.py index faa25dfbaa2..289ffa58b87 100644 --- a/erpnext/setup/setup_wizard/operations/taxes_setup.py +++ b/erpnext/setup/setup_wizard/operations/taxes_setup.py @@ -1,7 +1,6 @@ # Copyright (c) 2021, Frappe Technologies Pvt. Ltd. and Contributors # License: GNU General Public License v3. See license.txt -from __future__ import unicode_literals import os import json @@ -192,7 +191,7 @@ def get_or_create_account(company_name, account): default_root_type = 'Liability' root_type = account.get('root_type', default_root_type) - existing_accounts = frappe.get_list('Account', + existing_accounts = frappe.get_all('Account', filters={ 'company': company_name, 'root_type': root_type @@ -247,7 +246,7 @@ def get_or_create_tax_group(company_name, root_type): # Create a new group account named 'Duties and Taxes' or 'Tax Assets' just # below the root account - root_account = frappe.get_list('Account', { + root_account = frappe.get_all('Account', { 'is_group': 1, 'root_type': root_type, 'company': company_name, diff --git a/erpnext/setup/setup_wizard/setup_wizard.py b/erpnext/setup/setup_wizard/setup_wizard.py index ecb07d53b7c..c9ed184e04e 100644 --- a/erpnext/setup/setup_wizard/setup_wizard.py +++ b/erpnext/setup/setup_wizard/setup_wizard.py @@ -1,7 +1,6 @@ # Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors # License: GNU General Public License v3. See license.txt -from __future__ import unicode_literals import frappe from frappe import _ diff --git a/erpnext/setup/setup_wizard/utils.py b/erpnext/setup/setup_wizard/utils.py index 30b88aecbcd..f1ec50afcea 100644 --- a/erpnext/setup/setup_wizard/utils.py +++ b/erpnext/setup/setup_wizard/utils.py @@ -1,5 +1,3 @@ -from __future__ import unicode_literals - import json import os diff --git a/erpnext/setup/utils.py b/erpnext/setup/utils.py index 2302a66fa03..1478007da83 100644 --- a/erpnext/setup/utils.py +++ b/erpnext/setup/utils.py @@ -1,7 +1,6 @@ # Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors # License: GNU General Public License v3. See license.txt -from __future__ import unicode_literals import frappe from frappe import _ diff --git a/erpnext/setup/workspace/erpnext_settings/erpnext_settings.json b/erpnext/setup/workspace/erpnext_settings/erpnext_settings.json index ef4b050ceb2..1412acfcead 100644 --- a/erpnext/setup/workspace/erpnext_settings/erpnext_settings.json +++ b/erpnext/setup/workspace/erpnext_settings/erpnext_settings.json @@ -1,31 +1,21 @@ { - "category": "", "charts": [], - "content": "[{\"type\": \"header\", \"data\": {\"text\": \"Your Shortcuts\", \"level\": 4, \"col\": 12}}, {\"type\": \"shortcut\", \"data\": {\"shortcut_name\": \"Projects Settings\", \"col\": 4}}, {\"type\": \"shortcut\", \"data\": {\"shortcut_name\": \"Accounts Settings\", \"col\": 4}}, {\"type\": \"shortcut\", \"data\": {\"shortcut_name\": \"Stock Settings\", \"col\": 4}}, {\"type\": \"shortcut\", \"data\": {\"shortcut_name\": \"HR Settings\", \"col\": 4}}, {\"type\": \"shortcut\", \"data\": {\"shortcut_name\": \"Selling Settings\", \"col\": 4}}, {\"type\": \"shortcut\", \"data\": {\"shortcut_name\": \"Buying Settings\", \"col\": 4}}, {\"type\": \"shortcut\", \"data\": {\"shortcut_name\": \"Support Settings\", \"col\": 4}}, {\"type\": \"shortcut\", \"data\": {\"shortcut_name\": \"Shopping Cart Settings\", \"col\": 4}}, {\"type\": \"shortcut\", \"data\": {\"shortcut_name\": \"Portal Settings\", \"col\": 4}}, {\"type\": \"shortcut\", \"data\": {\"shortcut_name\": \"Manufacturing Settings\", \"col\": 4}}, {\"type\": \"shortcut\", \"data\": {\"shortcut_name\": \"Education Settings\", \"col\": 4}}, {\"type\": \"shortcut\", \"data\": {\"shortcut_name\": \"Hotel Settings\", \"col\": 4}}, {\"type\": \"shortcut\", \"data\": {\"shortcut_name\": \"Healthcare Settings\", \"col\": 4}}, {\"type\": \"shortcut\", \"data\": {\"shortcut_name\": \"Domain Settings\", \"col\": 4}}, {\"type\": \"shortcut\", \"data\": {\"shortcut_name\": \"Products Settings\", \"col\": 4}}]", + "content": "[{\"type\":\"header\",\"data\":{\"text\":\"Your Shortcuts\\n\\t\\t\\t\\n\\t\\t\\n\\t\\t\\t\\n\\t\\t\\n\\t\\t\\t\\n\\t\\t\",\"level\":4,\"col\":12}},{\"type\":\"shortcut\",\"data\":{\"shortcut_name\":\"Projects Settings\",\"col\":4}},{\"type\":\"shortcut\",\"data\":{\"shortcut_name\":\"Accounts Settings\",\"col\":4}},{\"type\":\"shortcut\",\"data\":{\"shortcut_name\":\"Stock Settings\",\"col\":4}},{\"type\":\"shortcut\",\"data\":{\"shortcut_name\":\"HR Settings\",\"col\":4}},{\"type\":\"shortcut\",\"data\":{\"shortcut_name\":\"Selling Settings\",\"col\":4}},{\"type\":\"shortcut\",\"data\":{\"shortcut_name\":\"Buying Settings\",\"col\":4}},{\"type\":\"shortcut\",\"data\":{\"shortcut_name\":\"Support Settings\",\"col\":4}},{\"type\":\"shortcut\",\"data\":{\"shortcut_name\":\"Shopping Cart Settings\",\"col\":4}},{\"type\":\"shortcut\",\"data\":{\"shortcut_name\":\"Portal Settings\",\"col\":4}},{\"type\":\"shortcut\",\"data\":{\"shortcut_name\":\"Domain Settings\",\"col\":4}},{\"type\":\"shortcut\",\"data\":{\"shortcut_name\":\"Products Settings\",\"col\":4}},{\"type\":\"shortcut\",\"data\":{\"shortcut_name\":\"Naming Series\",\"col\":4}}]", "creation": "2020-03-12 14:47:51.166455", - "developer_mode_only": 0, - "disable_user_customization": 0, "docstatus": 0, "doctype": "Workspace", - "extends": "", - "extends_another_page": 0, "for_user": "", "hide_custom": 0, "icon": "setting", "idx": 0, - "is_default": 0, - "is_standard": 0, "label": "ERPNext Settings", "links": [], - "modified": "2021-08-05 12:15:59.052327", + "modified": "2021-10-26 21:32:55.323591", "modified_by": "Administrator", "module": "Setup", "name": "ERPNext Settings", - "onboarding": "", "owner": "Administrator", "parent_page": "", - "pin_to_bottom": 0, - "pin_to_top": 0, "public": 1, "restrict_to_domain": "", "roles": [], @@ -37,6 +27,14 @@ "link_to": "Projects Settings", "type": "DocType" }, + { + "color": "Grey", + "doc_view": "", + "icon": "dot-horizontal", + "label": "Naming Series", + "link_to": "Naming Series", + "type": "DocType" + }, { "icon": "accounting", "label": "Accounts Settings", diff --git a/erpnext/setup/workspace/home/home.json b/erpnext/setup/workspace/home/home.json index a4e7ad863b0..4e1ccf9b94f 100644 --- a/erpnext/setup/workspace/home/home.json +++ b/erpnext/setup/workspace/home/home.json @@ -1,20 +1,13 @@ { - "category": "", "charts": [], - "content": "[{\"type\":\"header\",\"data\":{\"text\":\"Your Shortcuts\",\"level\":4,\"col\":12}},{\"type\":\"shortcut\",\"data\":{\"shortcut_name\":\"Item\",\"col\":4}},{\"type\":\"shortcut\",\"data\":{\"shortcut_name\":\"Customer\",\"col\":4}},{\"type\":\"shortcut\",\"data\":{\"shortcut_name\":\"Supplier\",\"col\":4}},{\"type\":\"shortcut\",\"data\":{\"shortcut_name\":\"Sales Invoice\",\"col\":4}},{\"type\":\"shortcut\",\"data\":{\"shortcut_name\":\"Leaderboard\",\"col\":4}},{\"type\":\"spacer\",\"data\":{\"col\":12}},{\"type\":\"header\",\"data\":{\"text\":\"Reports & Masters\",\"level\":4,\"col\":12}},{\"type\":\"card\",\"data\":{\"card_name\":\"Accounting\",\"col\":4}},{\"type\":\"card\",\"data\":{\"card_name\":\"Stock\",\"col\":4}},{\"type\":\"card\",\"data\":{\"card_name\":\"Human Resources\",\"col\":4}},{\"type\":\"card\",\"data\":{\"card_name\":\"CRM\",\"col\":4}},{\"type\":\"card\",\"data\":{\"card_name\":\"Data Import and Settings\",\"col\":4}}]", + "content": "[{\"type\":\"header\",\"data\":{\"text\":\"Your Shortcuts\",\"level\":4,\"col\":12}},{\"type\":\"shortcut\",\"data\":{\"shortcut_name\":\"Item\",\"col\":4}},{\"type\":\"shortcut\",\"data\":{\"shortcut_name\":\"Customer\",\"col\":4}},{\"type\":\"shortcut\",\"data\":{\"shortcut_name\":\"Supplier\",\"col\":4}},{\"type\":\"shortcut\",\"data\":{\"shortcut_name\":\"Sales Invoice\",\"col\":4}},{\"type\":\"shortcut\",\"data\":{\"shortcut_name\":\"Leaderboard\",\"col\":4}},{\"type\":\"spacer\",\"data\":{\"col\":12}},{\"type\":\"header\",\"data\":{\"text\":\"Reports & Masters\",\"level\":4,\"col\":12}},{\"type\":\"card\",\"data\":{\"card_name\":\"Accounting\",\"col\":4}},{\"type\":\"card\",\"data\":{\"card_name\":\"Stock\",\"col\":4}},{\"type\":\"card\",\"data\":{\"card_name\":\"Human Resources\",\"col\":4}},{\"type\":\"card\",\"data\":{\"card_name\":\"CRM\",\"col\":4}},{\"type\":\"card\",\"data\":{\"card_name\":\"Data Import and Settings\",\"col\":4}}]", "creation": "2020-01-23 13:46:38.833076", - "developer_mode_only": 0, - "disable_user_customization": 0, "docstatus": 0, "doctype": "Workspace", - "extends": "", - "extends_another_page": 0, "for_user": "", "hide_custom": 0, "icon": "getting-started", "idx": 0, - "is_default": 0, - "is_standard": 0, "label": "Home", "links": [ { @@ -278,15 +271,12 @@ "type": "Link" } ], - "modified": "2021-08-10 15:33:20.704740", + "modified": "2021-08-10 15:33:20.704741", "modified_by": "Administrator", "module": "Setup", "name": "Home", - "onboarding": "", "owner": "Administrator", "parent_page": "", - "pin_to_bottom": 0, - "pin_to_top": 0, "public": 1, "restrict_to_domain": "", "roles": [], diff --git a/erpnext/shopping_cart/cart.py b/erpnext/shopping_cart/cart.py index 3f1dfde0160..ebbe233ca3a 100644 --- a/erpnext/shopping_cart/cart.py +++ b/erpnext/shopping_cart/cart.py @@ -1,7 +1,6 @@ # Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors # License: GNU General Public License v3. See license.txt -from __future__ import unicode_literals import frappe import frappe.defaults @@ -195,7 +194,9 @@ def add_new_address(doc): def create_lead_for_item_inquiry(lead, subject, message): lead = frappe.parse_json(lead) lead_doc = frappe.new_doc('Lead') - lead_doc.update(lead) + for fieldname in ("lead_name", "company_name", "email_id", "phone"): + lead_doc.set(fieldname, lead.get(fieldname)) + lead_doc.set('lead_owner', '') if not frappe.db.exists('Lead Source', 'Product Inquiry'): @@ -203,6 +204,7 @@ def create_lead_for_item_inquiry(lead, subject, message): 'doctype': 'Lead Source', 'source_name' : 'Product Inquiry' }).insert(ignore_permissions=True) + lead_doc.set('source', 'Product Inquiry') try: diff --git a/erpnext/shopping_cart/doctype/shopping_cart_settings/shopping_cart_settings.py b/erpnext/shopping_cart/doctype/shopping_cart_settings/shopping_cart_settings.py index 8f4afda57e4..4a755998dd4 100644 --- a/erpnext/shopping_cart/doctype/shopping_cart_settings/shopping_cart_settings.py +++ b/erpnext/shopping_cart/doctype/shopping_cart_settings/shopping_cart_settings.py @@ -3,7 +3,6 @@ # For license information, please see license.txt -from __future__ import unicode_literals import frappe from frappe import _ diff --git a/erpnext/shopping_cart/doctype/shopping_cart_settings/test_shopping_cart_settings.py b/erpnext/shopping_cart/doctype/shopping_cart_settings/test_shopping_cart_settings.py index f8a22b0e020..c3809b30b0f 100644 --- a/erpnext/shopping_cart/doctype/shopping_cart_settings/test_shopping_cart_settings.py +++ b/erpnext/shopping_cart/doctype/shopping_cart_settings/test_shopping_cart_settings.py @@ -3,7 +3,6 @@ # For license information, please see license.txt -from __future__ import unicode_literals import unittest @@ -44,7 +43,6 @@ class TestShoppingCartSettings(unittest.TestCase): def test_tax_rule_validation(self): frappe.db.sql("update `tabTax Rule` set use_for_shopping_cart = 0") - frappe.db.commit() cart_settings = self.get_cart_settings() cart_settings.enabled = 1 diff --git a/erpnext/shopping_cart/filters.py b/erpnext/shopping_cart/filters.py index aaeff0fe073..ef0badc8c89 100644 --- a/erpnext/shopping_cart/filters.py +++ b/erpnext/shopping_cart/filters.py @@ -1,10 +1,8 @@ # Copyright (c) 2020, Frappe Technologies Pvt. Ltd. and Contributors # License: GNU General Public License v3. See license.txt -from __future__ import unicode_literals import frappe -from frappe import _dict class ProductFiltersBuilder: @@ -57,37 +55,31 @@ class ProductFiltersBuilder: return filter_data - def get_attribute_fitlers(self): + def get_attribute_filters(self): attributes = [row.attribute for row in self.doc.filter_attributes] - attribute_docs = [ - frappe.get_doc('Item Attribute', attribute) for attribute in attributes - ] - valid_attributes = [] + if not attributes: + return [] - for attr_doc in attribute_docs: - selected_attributes = [] - for attr in attr_doc.item_attribute_values: - or_filters = [] - filters= [ - ["Item Variant Attribute", "attribute", "=", attr.parent], - ["Item Variant Attribute", "attribute_value", "=", attr.attribute_value] - ] - if self.item_group: - or_filters.extend([ - ["item_group", "=", self.item_group], - ["Website Item Group", "item_group", "=", self.item_group] - ]) + result = frappe.db.sql( + """ + select + distinct attribute, attribute_value + from + `tabItem Variant Attribute` + where + attribute in %(attributes)s + and attribute_value is not null + """, + {"attributes": attributes}, + as_dict=1, + ) - if frappe.db.get_all("Item", filters, or_filters=or_filters, limit=1): - selected_attributes.append(attr) + attribute_value_map = {} + for d in result: + attribute_value_map.setdefault(d.attribute, []).append(d.attribute_value) - if selected_attributes: - valid_attributes.append( - _dict( - item_attribute_values=selected_attributes, - name=attr_doc.name - ) - ) - - return valid_attributes + out = [] + for name, values in attribute_value_map.items(): + out.append(frappe._dict(name=name, item_attribute_values=values)) + return out diff --git a/erpnext/shopping_cart/product_info.py b/erpnext/shopping_cart/product_info.py index fa6863696a8..977f12fb9ef 100644 --- a/erpnext/shopping_cart/product_info.py +++ b/erpnext/shopping_cart/product_info.py @@ -1,7 +1,6 @@ # Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors # License: GNU General Public License v3. See license.txt -from __future__ import unicode_literals import frappe diff --git a/erpnext/shopping_cart/test_shopping_cart.py b/erpnext/shopping_cart/test_shopping_cart.py index d1284cdf008..60c220a0878 100644 --- a/erpnext/shopping_cart/test_shopping_cart.py +++ b/erpnext/shopping_cart/test_shopping_cart.py @@ -1,7 +1,6 @@ # Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors # License: GNU General Public License v3. See license.txt -from __future__ import unicode_literals import unittest diff --git a/erpnext/shopping_cart/utils.py b/erpnext/shopping_cart/utils.py index f412e61f062..5f0c7923814 100644 --- a/erpnext/shopping_cart/utils.py +++ b/erpnext/shopping_cart/utils.py @@ -1,8 +1,5 @@ # Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors # License: GNU General Public License v3. See license.txt - -from __future__ import unicode_literals - import frappe from erpnext.shopping_cart.doctype.shopping_cart_settings.shopping_cart_settings import ( @@ -18,10 +15,19 @@ def show_cart_count(): return False def set_cart_count(login_manager): - role, parties = check_customer_or_supplier() - if role == 'Supplier': return + # since this is run only on hooks login event + # make sure user is already a customer + # before trying to set cart count + user_is_customer = is_customer() + if not user_is_customer: + return + if show_cart_count(): from erpnext.shopping_cart.cart import set_cart_count + + # set_cart_count will try to fetch existing cart quotation + # or create one if non existent (and create a customer too) + # cart count is calculated from this quotation's items set_cart_count() def clear_cart_count(login_manager): @@ -32,13 +38,13 @@ def update_website_context(context): cart_enabled = is_cart_enabled() context["shopping_cart_enabled"] = cart_enabled -def check_customer_or_supplier(): - if frappe.session.user: +def is_customer(): + if frappe.session.user and frappe.session.user != "Guest": contact_name = frappe.get_value("Contact", {"email_id": frappe.session.user}) if contact_name: contact = frappe.get_doc('Contact', contact_name) for link in contact.links: - if link.link_doctype in ('Customer', 'Supplier'): - return link.link_doctype, link.link_name + if link.link_doctype == 'Customer': + return True - return 'Customer', None + return False diff --git a/erpnext/shopping_cart/web_template/hero_slider/hero_slider.html b/erpnext/shopping_cart/web_template/hero_slider/hero_slider.html index 1e3d0d069a1..e560f4ad7de 100644 --- a/erpnext/shopping_cart/web_template/hero_slider/hero_slider.html +++ b/erpnext/shopping_cart/web_template/hero_slider/hero_slider.html @@ -1,7 +1,7 @@ {%- macro slide(image, title, subtitle, action, label, index, align="Left", theme="Dark") -%} {%- set align_class = resolve_class({ 'text-right': align == 'Right', - 'text-centre': align == 'Center', + 'text-centre': align == 'Centre', 'text-left': align == 'Left', }) -%} @@ -15,7 +15,7 @@